My Game
 
読み取り中…
検索中…
一致する文字列を見つけられません
imgui.cpp
[詳解]
1// dear imgui, v1.92.1
2// (main code and documentation)
3
4// Help:
5// - See links below.
6// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
7// - Read top of imgui.cpp for more details, links and comments.
8
9// Resources:
10// - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md)
11// - Homepage ................... https://github.com/ocornut/imgui
12// - Releases & changelog ....... https://github.com/ocornut/imgui/releases
13// - Gallery .................... https://github.com/ocornut/imgui/issues?q=label%3Agallery (please post your screenshots/video there!)
14// - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there)
15// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code)
16// - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more)
17// - Bindings/Backends https://github.com/ocornut/imgui/wiki/Bindings (language bindings, backends for various tech/engines)
18// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
19// - Debug Tools https://github.com/ocornut/imgui/wiki/Debug-Tools
20// - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui
21// - Issues & support ........... https://github.com/ocornut/imgui/issues
22// - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps)
23
24// For first-time users having issues compiling/linking/running:
25// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.
26// Everything else should be asked in 'Issues'! We are building a database of cross-linked knowledge there.
27// Since 1.92, we encourage font loading question to also be posted in 'Issues'.
28
29// Copyright (c) 2014-2025 Omar Cornut
30// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
31// See LICENSE.txt for copyright and licensing details (standard MIT License).
32// This library is free but needs your support to sustain development and maintenance.
33// Businesses: you can support continued development via B2B invoiced technical support, maintenance and sponsoring contracts.
34// PLEASE reach out at omar AT dearimgui DOT com. See https://github.com/ocornut/imgui/wiki/Funding
35// Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine.
36
37// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
38// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without
39// modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't
40// come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you
41// to a better solution or official support for them.
42
43/*
44
45Index of this file:
46
47DOCUMENTATION
48
49- MISSION STATEMENT
50- CONTROLS GUIDE
51- PROGRAMMER GUIDE
52 - READ FIRST
53 - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
54 - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
55 - HOW A SIMPLE APPLICATION MAY LOOK LIKE
56 - USING CUSTOM BACKEND / CUSTOM ENGINE
57- API BREAKING CHANGES (read me when you update!)
58- FREQUENTLY ASKED QUESTIONS (FAQ)
59 - Read all answers online: https://www.dearimgui.com/faq, or in docs/FAQ.md (with a Markdown viewer)
60
61CODE
62(search for "[SECTION]" in the code to find them)
63
64// [SECTION] INCLUDES
65// [SECTION] FORWARD DECLARATIONS
66// [SECTION] CONTEXT AND MEMORY ALLOCATORS
67// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO, ImGuiPlatformIO)
68// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
69// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
70// [SECTION] MISC HELPERS/UTILITIES (File functions)
71// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
72// [SECTION] MISC HELPERS/UTILITIES (Color functions)
73// [SECTION] ImGuiStorage
74// [SECTION] ImGuiTextFilter
75// [SECTION] ImGuiTextBuffer, ImGuiTextIndex
76// [SECTION] ImGuiListClipper
77// [SECTION] STYLING
78// [SECTION] RENDER HELPERS
79// [SECTION] INITIALIZATION, SHUTDOWN
80// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
81// [SECTION] FONTS
82// [SECTION] ID STACK
83// [SECTION] INPUTS
84// [SECTION] ERROR CHECKING, STATE RECOVERY
85// [SECTION] ITEM SUBMISSION
86// [SECTION] LAYOUT
87// [SECTION] SCROLLING
88// [SECTION] TOOLTIPS
89// [SECTION] POPUPS
90// [SECTION] WINDOW FOCUS
91// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
92// [SECTION] DRAG AND DROP
93// [SECTION] LOGGING/CAPTURING
94// [SECTION] SETTINGS
95// [SECTION] LOCALIZATION
96// [SECTION] VIEWPORTS, PLATFORM WINDOWS
97// [SECTION] DOCKING
98// [SECTION] PLATFORM DEPENDENT HELPERS
99// [SECTION] METRICS/DEBUGGER WINDOW
100// [SECTION] DEBUG LOG WINDOW
101// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, ID STACK TOOL)
102
103*/
104
105//-----------------------------------------------------------------------------
106// DOCUMENTATION
107//-----------------------------------------------------------------------------
108
109/*
110
111 MISSION STATEMENT
112 =================
113
114 - Easy to use to create code-driven and data-driven tools.
115 - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools.
116 - Easy to hack and improve.
117 - Minimize setup and maintenance.
118 - Minimize state storage on user side.
119 - Minimize state synchronization.
120 - Portable, minimize dependencies, run on target (consoles, phones, etc.).
121 - Efficient runtime and memory consumption.
122
123 Designed primarily for developers and content-creators, not the typical end-user!
124 Some of the current weaknesses (which we aim to address in the future) includes:
125
126 - Doesn't look fancy.
127 - Limited layout features, intricate layouts are typically crafted in code.
128
129
130 CONTROLS GUIDE
131 ==============
132
133 - MOUSE CONTROLS
134 - Mouse wheel: Scroll vertically.
135 - SHIFT+Mouse wheel: Scroll horizontally.
136 - Click [X]: Close a window, available when 'bool* p_open' is passed to ImGui::Begin().
137 - Click ^, Double-Click title: Collapse window.
138 - Drag on corner/border: Resize window (double-click to auto fit window to its contents).
139 - Drag on any empty space: Move window (unless io.ConfigWindowsMoveFromTitleBarOnly = true).
140 - Left-click outside popup: Close popup stack (right-click over underlying popup: Partially close popup stack).
141
142 - TEXT EDITOR
143 - Hold SHIFT or Drag Mouse: Select text.
144 - CTRL+Left/Right: Word jump.
145 - CTRL+Shift+Left/Right: Select words.
146 - CTRL+A or Double-Click: Select All.
147 - CTRL+X, CTRL+C, CTRL+V: Use OS clipboard.
148 - CTRL+Z Undo.
149 - CTRL+Y or CTRL+Shift+Z: Redo.
150 - ESCAPE: Revert text to its original value.
151 - On OSX, controls are automatically adjusted to match standard OSX text editing 2ts and behaviors.
152
153 - KEYBOARD CONTROLS
154 - Basic:
155 - Tab, SHIFT+Tab Cycle through text editable fields.
156 - CTRL+Tab, CTRL+Shift+Tab Cycle through windows.
157 - CTRL+Click Input text into a Slider or Drag widget.
158 - Extended features with `io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard`:
159 - Tab, SHIFT+Tab: Cycle through every items.
160 - Arrow keys Move through items using directional navigation. Tweak value.
161 - Arrow keys + Alt, Shift Tweak slower, tweak faster (when using arrow keys).
162 - Enter Activate item (prefer text input when possible).
163 - Space Activate item (prefer tweaking with arrows when possible).
164 - Escape Deactivate item, leave child window, close popup.
165 - Page Up, Page Down Previous page, next page.
166 - Home, End Scroll to top, scroll to bottom.
167 - Alt Toggle between scrolling layer and menu layer.
168 - CTRL+Tab then Ctrl+Arrows Move window. Hold SHIFT to resize instead of moving.
169 - Output when ImGuiConfigFlags_NavEnableKeyboard set,
170 - io.WantCaptureKeyboard flag is set when keyboard is claimed.
171 - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
172 - io.NavVisible: true when the navigation cursor is visible (usually goes to back false when mouse is used).
173
174 - GAMEPAD CONTROLS
175 - Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
176 - Particularly useful to use Dear ImGui on a console system (e.g. PlayStation, Switch, Xbox) without a mouse!
177 - Download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets
178 - Backend support: backend needs to:
179 - Set 'io.BackendFlags |= ImGuiBackendFlags_HasGamepad' + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys.
180 - For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly.
181 Backend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
182 - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing,
183 with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
184
185 - REMOTE INPUTS SHARING & MOUSE EMULATION
186 - PS4/PS5 users: Consider emulating a mouse cursor with DualShock touch pad or a spare analog stick as a mouse-emulation fallback.
187 - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + run examples/libs/synergy/uSynergy.c (on your console/tablet/phone app)
188 in order to share your PC mouse/keyboard.
189 - See https://github.com/ocornut/imgui/wiki/Useful-Extensions#remoting for other remoting solutions.
190 - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the io.ConfigNavMoveSetMousePos flag.
191 Enabling io.ConfigNavMoveSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs Dear ImGui to move your mouse cursor along with navigation movements.
192 When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved.
193 When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that.
194 (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, Dear ImGui will misbehave as it will see your mouse moving back & forth!)
195 (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want
196 to set a boolean to ignore your other external mouse positions until the external source is moved again.)
197
198
199 PROGRAMMER GUIDE
200 ================
201
202 READ FIRST
203 ----------
204 - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki)
205 - Your code creates the UI every frame of your application loop, if your code doesn't run the UI is gone!
206 The UI can be highly dynamic, there are no construction or destruction steps, less superfluous
207 data retention on your side, less state duplication, less state synchronization, fewer bugs.
208 - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
209 Or browse https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html for interactive web version.
210 - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build.
211 - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori).
212 You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki.
213 - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances.
214 For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI,
215 where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches.
216 - Our origin is on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right.
217 - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected).
218 If you get an assert, read the messages and comments around the assert.
219 - This codebase aims to be highly optimized:
220 - A typical idle frame should never call malloc/free.
221 - We rely on a maximum of constant-time or O(N) algorithms. Limiting searches/scans as much as possible.
222 - We put particular energy in making sure performances are decent with typical "Debug" build settings as well.
223 Which mean we tend to avoid over-relying on "zero-cost abstraction" as they aren't zero-cost at all.
224 - This codebase aims to be both highly opinionated and highly flexible:
225 - This code works because of the things it choose to solve or not solve.
226 - C++: this is a pragmatic C-ish codebase: we don't use fancy C++ features, we don't include C++ headers,
227 and ImGui:: is a namespace. We rarely use member functions (and when we did, I am mostly regretting it now).
228 This is to increase compatibility, increase maintainability and facilitate use from other languages.
229 - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types.
230 See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that.
231 We can can optionally export math operators for ImVec2/ImVec4 using IMGUI_DEFINE_MATH_OPERATORS, which we use internally.
232 - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction
233 (so don't use ImVector in your code or at our own risk!).
234 - Building: We don't use nor mandate a build system for the main library.
235 This is in an effort to ensure that it works in the real world aka with any esoteric build setup.
236 This is also because providing a build system for the main library would be of little-value.
237 The build problems are almost never coming from the main library but from specific backends.
238
239
240 HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
241 ----------------------------------------------
242 - Update submodule or copy/overwrite every file.
243 - About imconfig.h:
244 - You may modify your copy of imconfig.h, in this case don't overwrite it.
245 - or you may locally branch to modify imconfig.h and merge/rebase latest.
246 - or you may '#define IMGUI_USER_CONFIG "my_config_file.h"' globally from your build system to
247 specify a custom path for your imconfig.h file and instead not have to modify the default one.
248
249 - Overwrite all the sources files except for imconfig.h (if you have modified your copy of imconfig.h)
250 - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over "master".
251 - You can also use '#define IMGUI_USER_CONFIG "my_config_file.h" to redirect configuration to your own file.
252 - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
253 If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
254 from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will
255 likely be a comment about it. Please report any issue to the GitHub page!
256 - To find out usage of old API, you can add '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in your configuration file.
257 - Try to keep your copy of Dear ImGui reasonably up to date!
258
259
260 GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
261 ---------------------------------------------------------------
262 - See https://github.com/ocornut/imgui/wiki/Getting-Started.
263 - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
264 - In the majority of cases you should be able to use unmodified backends files available in the backends/ folder.
265 - Add the Dear ImGui source files + selected backend source files to your projects or using your preferred build system.
266 It is recommended you build and statically link the .cpp files as part of your project and NOT as a shared library (DLL).
267 - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types.
268 - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
269 - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.
270 Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render"
271 phases of your own application. All rendering information is stored into command-lists that you will retrieve after calling ImGui::Render().
272 - Refer to the backends and demo applications in the examples/ folder for instruction on how to setup your code.
273 - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder.
274
275
276 HOW A SIMPLE APPLICATION MAY LOOK LIKE
277 --------------------------------------
278
279 USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder).
280 The sub-folders in examples/ contain examples applications following this structure.
281
282 // Application init: create a dear imgui context, setup some options, load fonts
283 ImGui::CreateContext();
284 ImGuiIO& io = ImGui::GetIO();
285 // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
286 // TODO: Fill optional fields of the io structure later.
287 // TODO: Load TTF/OTF fonts if you don't want to use the default font.
288
289 // Initialize helper Platform and Renderer backends (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp)
290 ImGui_ImplWin32_Init(hwnd);
291 ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
292
293 // Application main loop
294 while (true)
295 {
296 // Feed inputs to dear imgui, start new frame
297 ImGui_ImplDX11_NewFrame();
298 ImGui_ImplWin32_NewFrame();
299 ImGui::NewFrame();
300
301 // Any application code here
302 ImGui::Text("Hello, world!");
303
304 // Render dear imgui into framebuffer
305 ImGui::Render();
306 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
307 g_pSwapChain->Present(1, 0);
308 }
309
310 // Shutdown
311 ImGui_ImplDX11_Shutdown();
312 ImGui_ImplWin32_Shutdown();
313 ImGui::DestroyContext();
314
315 To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application,
316 you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
317 Please read the FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" about this.
318
319
320USING CUSTOM BACKEND / CUSTOM ENGINE
321------------------------------------
322
323IMPLEMENTING YOUR PLATFORM BACKEND:
324 -> see https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md for basic instructions.
325 -> the Platform backends in impl_impl_XXX.cpp files contain many implementations.
326
327IMPLEMENTING YOUR RenderDrawData() function:
328 -> see https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md
329 -> the Renderer Backends in impl_impl_XXX.cpp files contain many implementations of a ImGui_ImplXXXX_RenderDrawData() function.
330
331IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
332 -> see https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md
333 -> the Renderer Backends in impl_impl_XXX.cpp files contain many implementations of a ImGui_ImplXXXX_UpdateTexture() function.
334
335 Basic application/backend skeleton:
336
337 // Application init: create a Dear ImGui context, setup some options, load fonts
338 ImGui::CreateContext();
339 ImGuiIO& io = ImGui::GetIO();
340 // TODO: set io.ConfigXXX values, e.g.
341 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable keyboard controls
342
343 // TODO: Load TTF/OTF fonts if you don't want to use the default font.
344 io.Fonts->AddFontFromFileTTF("NotoSans.ttf");
345
346 // Application main loop
347 while (true)
348 {
349 // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc.
350 // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform Backends)
351 io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds)
352 io.DisplaySize.x = 1920.0f; // set the current display width
353 io.DisplaySize.y = 1280.0f; // set the current display height here
354 io.AddMousePosEvent(mouse_x, mouse_y); // update mouse position
355 io.AddMouseButtonEvent(0, mouse_b[0]); // update mouse button states
356 io.AddMouseButtonEvent(1, mouse_b[1]); // update mouse button states
357
358 // Call NewFrame(), after this point you can use ImGui::* functions anytime
359 // (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere)
360 ImGui::NewFrame();
361
362 // Most of your application code here
363 ImGui::Text("Hello, world!");
364 MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
365 MyGameRender(); // may use any Dear ImGui functions as well!
366
367 // End the dear imgui frame
368 // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code)
369 ImGui::EndFrame(); // this is automatically called by Render(), but available
370 ImGui::Render();
371
372 // Update textures
373 ImDrawData* draw_data = ImGui::GetDrawData();
374 for (ImTextureData* tex : *draw_data->Textures)
375 if (tex->Status != ImTextureStatus_OK)
376 MyImGuiBackend_UpdateTexture(tex);
377
378 // Render dear imgui contents, swap buffers
379 MyImGuiBackend_RenderDrawData(draw_data);
380 SwapBuffers();
381 }
382
383 // Shutdown
384 ImGui::DestroyContext();
385
386
387
388 API BREAKING CHANGES
389 ====================
390
391 Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
392 Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
393 When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
394 You can read releases logs https://github.com/ocornut/imgui/releases for more details.
395
396(Docking/Viewport Branch)
397 - 2025/XX/XX (1.XXXX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that:
398 - reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore.
399 you may use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos)
400 - likewise io.MousePos and GetMousePos() will use OS coordinates.
401 If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
402
403 - 2025/06/25 (1.92.0) - layout: commented out legacy ErrorCheckUsingSetCursorPosToExtendParentBoundaries() fallback obsoleted in 1.89 (August 2022) which allowed a SetCursorPos()/SetCursorScreenPos() call WITHOUT AN ITEM
404 to extend parent window/cell boundaries. Replaced with assert/tooltip that would already happens if previously using IMGUI_DISABLE_OBSOLETE_FUNCTIONS. (#5548, #4510, #3355, #1760, #1490, #4152, #150)
405 - Incorrect way to make a window content size 200x200:
406 Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End();
407 - Correct ways to make a window content size 200x200:
408 Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End();
409 Begin(...) + Dummy(ImVec2(200,200)) + End();
410 - TL;DR; if the assert triggers, you can add a Dummy({0,0}) call to validate extending parent boundaries.
411>- 2025/06/11 (1.92.0) - Renamed/moved ImGuiConfigFlags_DpiEnableScaleFonts -> bool io.ConfigDpiScaleFonts.
412 - Renamed/moved ImGuiConfigFlags_DpiEnableScaleViewports -> bool io.ConfigDpiScaleViewports. **Neither of those flags are very useful in current code. They will be useful once we merge font changes.**
413 - 2025/06/11 (1.92.0) - THIS VERSION CONTAINS THE LARGEST AMOUNT OF BREAKING CHANGES SINCE 2015! I TRIED REALLY HARD TO KEEP THEM TO A MINIMUM, REDUCE THE AMOUNT OF INTERFERENCES, BUT INEVITABLY SOME USERS WILL BE AFFECTED.
414 IN ORDER TO HELP US IMPROVE THE TRANSITION PROCESS, INCL. DOCUMENTATION AND COMMENTS, PLEASE REPORT **ANY** DOUBT, CONFUSION, QUESTIONS, FEEDBACK TO: https://github.com/ocornut/imgui/issues/
415 As part of the plan to reduce impact of API breaking changes, several unfinished changes/features/refactors related to font and text systems and scaling will be part of subsequent releases (1.92.1+).
416 If you are updating from an old version, and expecting a massive or difficult update, consider first updating to 1.91.9 to reduce the amount of changes.
417 - Hard to read? Refer to 'docs/Changelog.txt' for a less compact and more complete version of this!
418 - Fonts: **IMPORTANT**: if your app was solving the OSX/iOS Retina screen specific logical vs display scale problem by setting io.DisplayFramebufferScale (e.g. to 2.0f) + setting io.FontGlobalScale (e.g. to 1.0f/2.0f) + loading fonts at scaled sizes (e.g. size X * 2.0f):
419 This WILL NOT map correctly to the new system! Because font will rasterize as requested size.
420 - With a legacy backend (< 1.92): Instead of setting io.FontGlobalScale = 1.0f/N -> set ImFontCfg::RasterizerDensity = N. This already worked before, but is now pretty much required.
421 - With a new backend (1.92+): This should be all automatic. FramebufferScale is automatically used to set current font RasterizerDensity. FramebufferScale is a per-viewport property provided by backend through the Platform_GetWindowFramebufferScale() handler in 'docking' branch.
422 - Fonts: **IMPORTANT** on Font Sizing: Before 1.92, fonts were of a single size. They can now be dynamically sized.
423 - PushFont() API now has a REQUIRED size parameter.
424 - Before 1.92: PushFont() always used font "default" size specified in AddFont() call. It is equivalent to calling PushFont(font, font->LegacySize).
425 - Since 1.92: PushFont(font, 0.0f) preserve the current font size which is a shared value.
426 - To use old behavior: use 'ImGui::PushFont(font, font->LegacySize)' at call site.
427 - Kept inline single parameter function. Will obsolete.
428 - Fonts: **IMPORTANT** on Font Merging:
429 - When searching for a glyph in multiple merged fonts: we search for the FIRST font source which contains the desired glyph.
430 Because the user doesn't need to provide glyph ranges any more, it is possible that a glyph that you expected to fetch from a secondary/merged icon font may be erroneously fetched from the primary font.
431 - When searching for a glyph in multiple merged fonts: we now search for the FIRST font source which contains the desired glyph. This is technically a different behavior than before!
432 - e.g. If you are merging fonts you may have glyphs that you expected to load from Font Source 2 which exists in Font Source 1.
433 After the update and when using a new backend, those glyphs may now loaded from Font Source 1!
434 - We added `ImFontConfig::GlyphExcludeRanges[]` to specify ranges to exclude from a given font source:
435 // Add Font Source 1 but ignore ICON_MIN_FA..ICON_MAX_FA range
436 static ImWchar exclude_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
437 ImFontConfig cfg1;
438 cfg1.GlyphExcludeRanges = exclude_ranges;
439 io.Fonts->AddFontFromFileTTF("segoeui.ttf", 0.0f, &cfg1);
440 // Add Font Source 2, which expects to use the range above
441 ImFontConfig cfg2;
442 cfg2.MergeMode = true;
443 io.Fonts->AddFontFromFileTTF("FontAwesome4.ttf", 0.0f, &cfg2);
444 - You can use `Metrics/Debugger->Fonts->Font->Input Glyphs Overlap Detection Tool` to see list of glyphs available in multiple font sources. This can facilitate unde
445 - Fonts: ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont().
446 - Fonts: Removed support for PushFont(NULL) which was a shortcut for "default font".
447 - Fonts: Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'.
448 - Textures: all API functions taking a 'ImTextureID' parameter are now taking a 'ImTextureRef'. Affected functions are: ImGui::Image(), ImGui::ImageWithBg(), ImGui::ImageButton(), ImDrawList::AddImage(), ImDrawList::AddImageQuad(), ImDrawList::AddImageRounded().
449 - Fonts: obsoleted ImFontAtlas::GetTexDataAsRGBA32(), GetTexDataAsAlpha8(), Build(), SetTexID(), IsBuilt() functions. The new protocol for backends to handle textures doesn't need them. Kept redirection functions (will obsolete).
450 - Fonts: ImFontConfig::OversampleH/OversampleV default to automatic (== 0) since v1.91.8. It is quite important you keep it automatic until we decide if we want to provide a way to express finer policy, otherwise you will likely waste texture space when using large glyphs. Note that the imgui_freetype backend doesn't use and does not need oversampling.
451 - Fonts: specifying glyph ranges is now unnecessary. The value of ImFontConfig::GlyphRanges[] is only useful for legacy backends. All GetGlyphRangesXXXX() functions are now marked obsolete: GetGlyphRangesDefault(), GetGlyphRangesGreek(), GetGlyphRangesKorean(), GetGlyphRangesJapanese(), GetGlyphRangesChineseSimplifiedCommon(), GetGlyphRangesChineseFull(), GetGlyphRangesCyrillic(), GetGlyphRangesThai(), GetGlyphRangesVietnamese().
452 - Fonts: removed ImFontAtlas::TexDesiredWidth to enforce a texture width. (#327)
453 - Fonts: if you create and manage ImFontAtlas instances yourself (instead of relying on ImGuiContext to create one, you'll need to call ImFontAtlasUpdateNewFrame() yourself. An assert will trigger if you don't.
454 - Fonts: obsolete ImGui::SetWindowFontScale() which is not useful anymore. Prefer using 'PushFont(NULL, style.FontSizeBase * factor)' or to manipulate other scaling factors.
455 - Fonts: obsoleted ImFont::Scale which is not useful anymore.
456 - Fonts: generally reworked Internals of ImFontAtlas and ImFont. While in theory a vast majority of users shouldn't be affected, some use cases or extensions might be. Among other things:
457 - ImDrawCmd::TextureId has been changed to ImDrawCmd::TexRef.
458 - ImFontAtlas::TexID has been changed to ImFontAtlas::TexRef.
459 - ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[]
460 - ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourceCount.
461 - Each ImFont has a number of ImFontBaked instances corresponding to actively used sizes. ImFont::GetFontBaked(size) retrieves the one for a given size.
462 - Fields moved from ImFont to ImFontBaked: IndexAdvanceX[], Glyphs[], Ascent, Descent, FindGlyph(), FindGlyphNoFallback(), GetCharAdvance().
463 - Fields moved from ImFontAtlas to ImFontAtlas->Tex: ImFontAtlas::TexWidth => TexData->Width, ImFontAtlas::TexHeight => TexData->Height, ImFontAtlas::TexPixelsAlpha8/TexPixelsRGBA32 => TexData->GetPixels().
464 - Widget code may use ImGui::GetFontBaked() instead of ImGui::GetFont() to access font data for current font at current font size (and you may use font->GetFontBaked(size) to access it for any other size.)
465 - Fonts: (users of imgui_freetype): renamed ImFontAtlas::FontBuilderFlags to ImFontAtlas::FontLoaderFlags. Renamed ImFontConfig::FontBuilderFlags to ImFontConfig::FontLoaderFlags. Renamed ImGuiFreeTypeBuilderFlags to ImGuiFreeTypeLoaderFlags.
466 If you used runtime imgui_freetype selection rather than the default IMGUI_ENABLE_FREETYPE compile-time option: Renamed/reworked ImFontBuilderIO into ImFontLoader. Renamed ImGuiFreeType::GetBuilderForFreeType() to ImGuiFreeType::GetFontLoader().
467 - old: io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()
468 - new: io.Fonts->FontLoader = ImGuiFreeType::GetFontLoader()
469 - new: io.Fonts->SetFontLoader(ImGuiFreeType::GetFontLoader()) to change dynamically at runtime [from 1.92.1]
470 - Fonts: (users of custom rectangles, see #8466): Renamed AddCustomRectRegular() to AddCustomRect(). Added GetCustomRect() as a replacement for GetCustomRectByIndex() + CalcCustomRectUV().
471 - The output type of GetCustomRect() is now ImFontAtlasRect, which include UV coordinates. X->x, Y->y, Width->w, Height->h.
472 - old:
473 const ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(custom_rect_id);
474 ImVec2 uv0, uv1;
475 atlas->GetCustomRectUV(r, &uv0, &uv1);
476 ImGui::Image(atlas->TexRef, ImVec2(r->w, r->h), uv0, uv1);
477 - new;
478 ImFontAtlasRect r;
479 atlas->GetCustomRect(custom_rect_id, &r);
480 ImGui::Image(atlas->TexRef, ImVec2(r.w, r.h), r.uv0, r.uv1);
481 - We added a redirecting typedef but haven't attempted to magically redirect the field names, as this API is rarely used and the fix is simple.
482 - Obsoleted AddCustomRectFontGlyph() as the API does not make sense for scalable fonts. Kept existing function which uses the font "default size" (Sources[0]->LegacySize). Added a helper AddCustomRectFontGlyphForSize() which is immediately marked obsolete, but can facilitate transitioning old code.
483 - Prefer adding a font source (ImFontConfig) using a custom/procedural loader.
484 - DrawList: Renamed ImDrawList::PushTextureID()/PopTextureID() to PushTexture()/PopTexture().
485 - Backends: removed ImGui_ImplXXXX_CreateFontsTexture()/ImGui_ImplXXXX_DestroyFontsTexture() for all backends that had them. They should not be necessary any more.
486 - 2025/05/23 (1.92.0) - Fonts: changed ImFont::CalcWordWrapPositionA() to ImFont::CalcWordWrapPosition()
487 - old: const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, ....);
488 - new: const char* ImFont::CalcWordWrapPosition (float size, const char* text, ....);
489 The leading 'float scale' parameters was changed to 'float size'. This was necessary as 'scale' is assuming standard font size which is a concept we aim to eliminate in an upcoming update. Kept inline redirection function.
490 - 2025/05/15 (1.92.0) - TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent for clarity. Kept inline redirection enum (will obsolete).
491 - 2025/05/15 (1.92.0) - Commented out PushAllowKeyboardFocus()/PopAllowKeyboardFocus() which was obsoleted in 1.89.4. Use PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop)/PopItemFlag() instead. (#3092)
492 - 2025/05/15 (1.92.0) - Commented out ImGuiListClipper::ForceDisplayRangeByIndices() which was obsoleted in 1.89.6. Use ImGuiListClipper::IncludeItemsByIndex() instead.
493 - 2025/03/05 (1.91.9) - BeginMenu(): Internals: reworked mangling of menu windows to use "###Menu_00" etc. instead of "##Menu_00", allowing them to also store the menu name before it. This shouldn't affect code unless directly accessing menu window from their mangled name.
494 - 2025/04/16 (1.91.9) - Internals: RenderTextEllipsis() function removed the 'float clip_max_x' parameter directly preceding 'float ellipsis_max_x'. Values were identical for a vast majority of users. (#8387)
495 - 2025/02/27 (1.91.9) - Image(): removed 'tint_col' and 'border_col' parameter from Image() function. Added ImageWithBg() replacement. (#8131, #8238)
496 - old: void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1), ImVec4 tint_col = (1,1,1,1), ImVec4 border_col = (0,0,0,0));
497 - new: void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1));
498 - new: void ImageWithBg(ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1), ImVec4 bg_col = (0,0,0,0), ImVec4 tint_col = (1,1,1,1));
499 - TL;DR: 'border_col' had misleading side-effect on layout, 'bg_col' was missing, parameter order couldn't be consistent with ImageButton().
500 - new behavior always use ImGuiCol_Border color + style.ImageBorderSize / ImGuiStyleVar_ImageBorderSize.
501 - old behavior altered border size (and therefore layout) based on border color's alpha, which caused variety of problems + old behavior a fixed 1.0f for border size which was not tweakable.
502 - kept legacy signature (will obsolete), which mimics the old behavior, but uses Max(1.0f, style.ImageBorderSize) when border_col is specified.
503 - added ImageWithBg() function which has both 'bg_col' (which was missing) and 'tint_col'. It was impossible to add 'bg_col' to Image() with a parameter order consistent with other functions, so we decided to remove 'tint_col' and introduce ImageWithBg().
504 - 2025/02/25 (1.91.9) - internals: fonts: ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[]. ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourcesCount.
505 - 2025/02/06 (1.91.9) - renamed ImFontConfig::GlyphExtraSpacing.x to ImFontConfig::GlyphExtraAdvanceX.
506 - 2025/01/22 (1.91.8) - removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior.
507 prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior.
508 the new flags (ImGuiColorEditFlags_AlphaOpaque, ImGuiColorEditFlags_AlphaNoBg + existing ImGuiColorEditFlags_AlphaPreviewHalf) may be combined better and allow finer controls:
509 - 2025/01/14 (1.91.7) - renamed ImGuiTreeNodeFlags_SpanTextWidth to ImGuiTreeNodeFlags_SpanLabelWidth for consistency with other names. Kept redirection enum (will obsolete). (#6937)
510 - 2024/11/27 (1.91.6) - changed CRC32 table from CRC32-adler to CRC32c polynomial in order to be compatible with the result of SSE 4.2 instructions.
511 As a result, old .ini data may be partially lost (docking and tables information particularly).
512 Because some users have crafted and storing .ini data as a way to workaround limitations of the docking API, we are providing a '#define IMGUI_USE_LEGACY_CRC32_ADLER' compile-time option to keep using old CRC32 tables if you cannot afford invalidating old .ini data.
513 - 2024/11/06 (1.91.5) - commented/obsoleted out pre-1.87 IO system (equivalent to using IMGUI_DISABLE_OBSOLETE_KEYIO or IMGUI_DISABLE_OBSOLETE_FUNCTIONS before)
514 - io.KeyMap[] and io.KeysDown[] are removed (obsoleted February 2022).
515 - io.NavInputs[] and ImGuiNavInput are removed (obsoleted July 2022).
516 - pre-1.87 backends are not supported:
517 - backends need to call io.AddKeyEvent(), io.AddMouseEvent() instead of writing to io.KeysDown[], io.MouseDown[] fields.
518 - backends need to call io.AddKeyAnalogEvent() for gamepad values instead of writing to io.NavInputs[] fields.
519 - for more reference:
520 - read 1.87 and 1.88 part of this section or read Changelog for 1.87 and 1.88.
521 - read https://github.com/ocornut/imgui/issues/4921
522 - if you have trouble updating a very old codebase using legacy backend-specific key codes: consider updating to 1.91.4 first, then #define IMGUI_DISABLE_OBSOLETE_KEYIO, then update to latest.
523 - obsoleted ImGuiKey_COUNT (it is unusually error-prone/misleading since valid keys don't start at 0). probably use ImGuiKey_NamedKey_BEGIN/ImGuiKey_NamedKey_END?
524 - fonts: removed const qualifiers from most font functions in prevision for upcoming font improvements.
525 - 2024/10/18 (1.91.4) - renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor (for consistency with newly exposed and reworked features). Kept inline redirection enum (will obsolete).
526 - 2024/10/14 (1.91.4) - moved ImGuiConfigFlags_NavEnableSetMousePos to standalone io.ConfigNavMoveSetMousePos bool.
527 moved ImGuiConfigFlags_NavNoCaptureKeyboard to standalone io.ConfigNavCaptureKeyboard bool (note the inverted value!).
528 kept legacy names (will obsolete) + code that copies settings once the first time. Dynamically changing the old value won't work. Switch to using the new value!
529 - 2024/10/10 (1.91.4) - the typedef for ImTextureID now defaults to ImU64 instead of void*. (#1641)
530 this removes the requirement to redefine it for backends which are e.g. storing descriptor sets or other 64-bits structures when building on 32-bits archs. It therefore simplify various building scripts/helpers.
531 you may have compile-time issues if you were casting to 'void*' instead of 'ImTextureID' when passing your types to functions taking ImTextureID values, e.g. ImGui::Image().
532 in doubt it is almost always better to do an intermediate intptr_t cast, since it allows casting any pointer/integer type without warning:
533 - May warn: ImGui::Image((void*)MyTextureData, ...);
534 - May warn: ImGui::Image((void*)(intptr_t)MyTextureData, ...);
535 - Won't warn: ImGui::Image((ImTextureID)(intptr_t)MyTextureData), ...);
536 - note that you can always define ImTextureID to be your own high-level structures (with dedicated constructors) if you like.
537 - 2024/10/03 (1.91.3) - drags: treat v_min==v_max as a valid clamping range when != 0.0f. Zero is a still special value due to legacy reasons, unless using ImGuiSliderFlags_ClampZeroRange. (#7968, #3361, #76)
538 - drags: extended behavior of ImGuiSliderFlags_AlwaysClamp to include _ClampZeroRange. It considers v_min==v_max==0.0f as a valid clamping range (aka edits not allowed).
539 although unlikely, it you wish to only clamp on text input but want v_min==v_max==0.0f to mean unclamped drags, you can use _ClampOnInput instead of _AlwaysClamp. (#7968, #3361, #76)
540 - 2024/09/10 (1.91.2) - internals: using multiple overlaid ButtonBehavior() with same ID will now have io.ConfigDebugHighlightIdConflicts=true feature emit a warning. (#8030)
541 it was one of the rare case where using same ID is legal. workarounds: (1) use single ButtonBehavior() call with multiple _MouseButton flags, or (2) surround the calls with PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag()
542 - 2024/08/23 (1.91.1) - renamed ImGuiChildFlags_Border to ImGuiChildFlags_Borders for consistency. kept inline redirection flag.
543 - 2024/08/22 (1.91.1) - moved some functions from ImGuiIO to ImGuiPlatformIO structure:
544 - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn + changed 'void* user_data' to 'ImGuiContext* ctx'. Pull your user data from platform_io.ClipboardUserData.
545 - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn + same as above line.
546 - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn (#7660)
547 - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn
548 - io.PlatformLocaleDecimalPoint -> platform_io.Platform_LocaleDecimalPoint (#7389, #6719, #2278)
549 - access those via GetPlatformIO() instead of GetIO().
550 some were introduced very recently and often automatically setup by core library and backends, so for those we are exceptionally not maintaining a legacy redirection symbol.
551 - commented the old ImageButton() signature obsoleted in 1.89 (~August 2022). As a reminder:
552 - old ImageButton() before 1.89 used ImTextureId as item id (created issue with e.g. multiple buttons in same scope, transient texture id values, opaque computation of ID)
553 - new ImageButton() since 1.89 requires an explicit 'const char* str_id'
554 - old ImageButton() before 1.89 had frame_padding' override argument.
555 - new ImageButton() since 1.89 always use style.FramePadding, which you can freely override with PushStyleVar()/PopStyleVar().
556 - 2024/07/25 (1.91.0) - obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). (see #7838 on GitHub for more info)
557 you should never need those functions. you can do everything with GetCursorScreenPos() and GetContentRegionAvail() in a more simple way.
558 - instead of: GetWindowContentRegionMax().x - GetCursorPos().x
559 - you can use: GetContentRegionAvail().x
560 - instead of: GetWindowContentRegionMax().x + GetWindowPos().x
561 - you can use: GetCursorScreenPos().x + GetContentRegionAvail().x // when called from left edge of window
562 - instead of: GetContentRegionMax()
563 - you can use: GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos() // right edge in local coordinates
564 - instead of: GetWindowContentRegionMax().x - GetWindowContentRegionMin().x
565 - you can use: GetContentRegionAvail() // when called from left edge of window
566 - 2024/07/15 (1.91.0) - renamed ImGuiSelectableFlags_DontClosePopups to ImGuiSelectableFlags_NoAutoClosePopups. (#1379, #1468, #2200, #4936, #5216, #7302, #7573)
567 (internals: also renamed ImGuiItemFlags_SelectableDontClosePopup into ImGuiItemFlags_AutoClosePopups with inverted behaviors)
568 - 2024/07/15 (1.91.0) - obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag(ImGuiItemFlags_ButtonRepeat, ...)/PopItemFlag().
569 - 2024/07/02 (1.91.0) - commented out obsolete ImGuiModFlags (renamed to ImGuiKeyChord in 1.89). (#4921, #456)
570 - commented out obsolete ImGuiModFlags_XXX values (renamed to ImGuiMod_XXX in 1.89). (#4921, #456)
571 - ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl, ImGuiModFlags_Shift -> ImGuiMod_Shift etc.
572 - 2024/07/02 (1.91.0) - IO, IME: renamed platform IME hook and added explicit context for consistency and future-proofness.
573 - old: io.SetPlatformImeDataFn(ImGuiViewport* viewport, ImGuiPlatformImeData* data);
574 - new: io.PlatformSetImeDataFn(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data);
575 - 2024/06/21 (1.90.9) - BeginChild: added ImGuiChildFlags_NavFlattened as a replacement for the window flag ImGuiWindowFlags_NavFlattened: the feature only ever made sense for BeginChild() anyhow.
576 - old: BeginChild("Name", size, 0, ImGuiWindowFlags_NavFlattened);
577 - new: BeginChild("Name", size, ImGuiChildFlags_NavFlattened, 0);
578 - 2024/06/21 (1.90.9) - io: ClearInputKeys() (first exposed in 1.89.8) doesn't clear mouse data, newly added ClearInputMouse() does.
579 - 2024/06/20 (1.90.9) - renamed ImGuiDragDropFlags_SourceAutoExpirePayload to ImGuiDragDropFlags_PayloadAutoExpire.
580 - 2024/06/18 (1.90.9) - style: renamed ImGuiCol_TabActive -> ImGuiCol_TabSelected, ImGuiCol_TabUnfocused -> ImGuiCol_TabDimmed, ImGuiCol_TabUnfocusedActive -> ImGuiCol_TabDimmedSelected.
581 - 2024/06/10 (1.90.9) - removed old nested structure: renaming ImGuiStorage::ImGuiStoragePair type to ImGuiStoragePair (simpler for many languages).
582 - 2024/06/06 (1.90.8) - reordered ImGuiInputTextFlags values. This should not be breaking unless you are using generated headers that have values not matching the main library.
583 - 2024/06/06 (1.90.8) - removed 'ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft', was mostly unused and misleading.
584 - 2024/05/27 (1.90.7) - commented out obsolete symbols marked obsolete in 1.88 (May 2022):
585 - old: CaptureKeyboardFromApp(bool)
586 - new: SetNextFrameWantCaptureKeyboard(bool)
587 - old: CaptureMouseFromApp(bool)
588 - new: SetNextFrameWantCaptureMouse(bool)
589 - 2024/05/22 (1.90.7) - inputs (internals): renamed ImGuiKeyOwner_None to ImGuiKeyOwner_NoOwner, to make use more explicit and reduce confusion with the default it is a non-zero value and cannot be the default value (never made public, but disclosing as I expect a few users caught on owner-aware inputs).
590 - inputs (internals): renamed ImGuiInputFlags_RouteGlobalLow -> ImGuiInputFlags_RouteGlobal, ImGuiInputFlags_RouteGlobal -> ImGuiInputFlags_RouteGlobalOverFocused, ImGuiInputFlags_RouteGlobalHigh -> ImGuiInputFlags_RouteGlobalHighest.
591 - inputs (internals): Shortcut(), SetShortcutRouting(): swapped last two parameters order in function signatures:
592 - old: Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id = 0, ImGuiInputFlags flags = 0);
593 - new: Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0, ImGuiID owner_id = 0);
594 - inputs (internals): owner-aware versions of IsKeyPressed(), IsKeyChordPressed(), IsMouseClicked(): swapped last two parameters order in function signatures.
595 - old: IsKeyPressed(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0);
596 - new: IsKeyPressed(ImGuiKey key, ImGuiInputFlags flags, ImGuiID owner_id = 0);
597 - old: IsMouseClicked(ImGuiMouseButton button, ImGuiID owner_id, ImGuiInputFlags flags = 0);
598 - new: IsMouseClicked(ImGuiMouseButton button, ImGuiInputFlags flags, ImGuiID owner_id = 0);
599 for various reasons those changes makes sense. They are being made because making some of those API public.
600 only past users of imgui_internal.h with the extra parameters will be affected. Added asserts for valid flags in various functions to detect _some_ misuses, BUT NOT ALL.
601 - 2024/05/21 (1.90.7) - docking: changed signature of DockSpaceOverViewport() to add explicit dockspace id if desired. pass 0 to use old behavior. (#7611)
602 - old: DockSpaceOverViewport(const ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, ...);
603 - new: DockSpaceOverViewport(ImGuiID dockspace_id = 0, const ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, ...);
604 - 2024/05/16 (1.90.7) - inputs: on macOS X, Cmd and Ctrl keys are now automatically swapped by io.AddKeyEvent() as this naturally align with how macOS X uses those keys.
605 - it shouldn't really affect you unless you had custom shortcut swapping in place for macOS X apps.
606 - removed ImGuiMod_Shortcut which was previously dynamically remapping to Ctrl or Cmd/Super. It is now unnecessary to specific cross-platform idiomatic shortcuts. (#2343, #4084, #5923, #456)
607 - 2024/05/14 (1.90.7) - backends: SDL_Renderer2 and SDL_Renderer3 backend now take a SDL_Renderer* in their RenderDrawData() functions.
608 - 2024/04/18 (1.90.6) - TreeNode: Fixed a layout inconsistency when using an empty/hidden label followed by a SameLine() call. (#7505, #282)
609 - old: TreeNode("##Hidden"); SameLine(); Text("Hello"); // <-- This was actually incorrect! BUT appeared to look ok with the default style where ItemSpacing.x == FramePadding.x * 2 (it didn't look aligned otherwise).
610 - new: TreeNode("##Hidden"); SameLine(0, 0); Text("Hello"); // <-- This is correct for all styles values.
611 with the fix, IF you were successfully using TreeNode("")+SameLine(); you will now have extra spacing between your TreeNode and the following item.
612 You'll need to change the SameLine() call to SameLine(0,0) to remove this extraneous spacing. This seemed like the more sensible fix that's not making things less consistent.
613 (Note: when using this idiom you are likely to also use ImGuiTreeNodeFlags_SpanAvailWidth).
614 - 2024/03/18 (1.90.5) - merged the radius_x/radius_y parameters in ImDrawList::AddEllipse(), AddEllipseFilled() and PathEllipticalArcTo() into a single ImVec2 parameter. Exceptionally, because those functions were added in 1.90, we are not adding inline redirection functions. The transition is easy and should affect few users. (#2743, #7417)
615 - 2024/03/08 (1.90.5) - inputs: more formally obsoleted GetKeyIndex() when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is set. It has been unnecessary and a no-op since 1.87 (it returns the same value as passed when used with a 1.87+ backend using io.AddKeyEvent() function). (#4921)
616 - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX)
617 - 2024/01/15 (1.90.2) - commented out obsolete ImGuiIO::ImeWindowHandle marked obsolete in 1.87, favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'.
618 - 2023/12/19 (1.90.1) - commented out obsolete ImGuiKey_KeyPadEnter redirection to ImGuiKey_KeypadEnter.
619 - 2023/11/06 (1.90.1) - removed CalcListClipping() marked obsolete in 1.86. Prefer using ImGuiListClipper which can return non-contiguous ranges.
620 - 2023/11/05 (1.90.1) - imgui_freetype: commented out ImGuiFreeType::BuildFontAtlas() obsoleted in 1.81. prefer using #define IMGUI_ENABLE_FREETYPE or see commented code for manual calls.
621 - 2023/11/05 (1.90.1) - internals,columns: commented out legacy ImGuiColumnsFlags_XXX symbols redirecting to ImGuiOldColumnsFlags_XXX, obsoleted from imgui_internal.h in 1.80.
622 - 2023/11/09 (1.90.0) - removed IM_OFFSETOF() macro in favor of using offsetof() available in C++11. Kept redirection define (will obsolete).
623 - 2023/11/07 (1.90.0) - removed BeginChildFrame()/EndChildFrame() in favor of using BeginChild() with the ImGuiChildFlags_FrameStyle flag. kept inline redirection function (will obsolete).
624 those functions were merely PushStyle/PopStyle helpers, the removal isn't so much motivated by needing to add the feature in BeginChild(), but by the necessity to avoid BeginChildFrame() signature mismatching BeginChild() signature and features.
625 - 2023/11/02 (1.90.0) - BeginChild: upgraded 'bool border = true' parameter to 'ImGuiChildFlags flags' type, added ImGuiChildFlags_Border equivalent. As with our prior "bool-to-flags" API updates, the ImGuiChildFlags_Border value is guaranteed to be == true forever to ensure a smoother transition, meaning all existing calls will still work.
626 - old: BeginChild("Name", size, true)
627 - new: BeginChild("Name", size, ImGuiChildFlags_Border)
628 - old: BeginChild("Name", size, false)
629 - new: BeginChild("Name", size) or BeginChild("Name", 0) or BeginChild("Name", size, ImGuiChildFlags_None)
630 **AMEND FROM THE FUTURE: from 1.91.1, 'ImGuiChildFlags_Border' is called 'ImGuiChildFlags_Borders'**
631 - 2023/11/02 (1.90.0) - BeginChild: added child-flag ImGuiChildFlags_AlwaysUseWindowPadding as a replacement for the window-flag ImGuiWindowFlags_AlwaysUseWindowPadding: the feature only ever made sense for BeginChild() anyhow.
632 - old: BeginChild("Name", size, 0, ImGuiWindowFlags_AlwaysUseWindowPadding);
633 - new: BeginChild("Name", size, ImGuiChildFlags_AlwaysUseWindowPadding, 0);
634 - 2023/09/27 (1.90.0) - io: removed io.MetricsActiveAllocations introduced in 1.63. Same as 'g.DebugMemAllocCount - g.DebugMemFreeCount' (still displayed in Metrics, unlikely to be accessed by end-user).
635 - 2023/09/26 (1.90.0) - debug tools: Renamed ShowStackToolWindow() ("Stack Tool") to ShowIDStackToolWindow() ("ID Stack Tool"), as earlier name was misleading. Kept inline redirection function. (#4631)
636 - 2023/09/15 (1.90.0) - ListBox, Combo: changed signature of "name getter" callback in old one-liner ListBox()/Combo() apis. kept inline redirection function (will obsolete).
637 - old: bool Combo(const char* label, int* current_item, bool (*getter)(void* user_data, int idx, const char** out_text), ...)
638 - new: bool Combo(const char* label, int* current_item, const char* (*getter)(void* user_data, int idx), ...);
639 - old: bool ListBox(const char* label, int* current_item, bool (*getting)(void* user_data, int idx, const char** out_text), ...);
640 - new: bool ListBox(const char* label, int* current_item, const char* (*getter)(void* user_data, int idx), ...);
641 - 2023/09/08 (1.90.0) - commented out obsolete redirecting functions:
642 - GetWindowContentRegionWidth() -> use GetWindowContentRegionMax().x - GetWindowContentRegionMin().x. Consider that generally 'GetContentRegionAvail().x' is more useful.
643 - ImDrawCornerFlags_XXX -> use ImDrawFlags_RoundCornersXXX flags. Read 1.82 Changelog for details + grep commented names in sources.
644 - commented out runtime support for hardcoded ~0 or 0x01..0x0F rounding flags values for AddRect()/AddRectFilled()/PathRect()/AddImageRounded() -> use ImDrawFlags_RoundCornersXXX flags. Read 1.82 Changelog for details
645 - 2023/08/25 (1.89.9) - clipper: Renamed IncludeRangeByIndices() (also called ForceDisplayRangeByIndices() before 1.89.6) to IncludeItemsByIndex(). Kept inline redirection function. Sorry!
646 - 2023/07/12 (1.89.8) - ImDrawData: CmdLists now owned, changed from ImDrawList** to ImVector<ImDrawList*>. Majority of users shouldn't be affected, but you cannot compare to NULL nor reassign manually anymore. Instead use AddDrawList(). (#6406, #4879, #1878)
647 - 2023/06/28 (1.89.7) - overlapping items: obsoleted 'SetItemAllowOverlap()' (called after item) in favor of calling 'SetNextItemAllowOverlap()' (called before item). 'SetItemAllowOverlap()' didn't and couldn't work reliably since 1.89 (2022-11-15).
648 - 2023/06/28 (1.89.7) - overlapping items: renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete).
649 - 2023/06/28 (1.89.7) - overlapping items: IsItemHovered() now by default return false when querying an item using AllowOverlap mode which is being overlapped. Use ImGuiHoveredFlags_AllowWhenOverlappedByItem to revert to old behavior.
650 - 2023/06/28 (1.89.7) - overlapping items: Selectable and TreeNode don't allow overlap when active so overlapping widgets won't appear as hovered. While this fixes a common small visual issue, it also means that calling IsItemHovered() after a non-reactive elements - e.g. Text() - overlapping an active one may fail if you don't use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem). (#6610)
651 - 2023/06/20 (1.89.7) - moved io.HoverDelayShort/io.HoverDelayNormal to style.HoverDelayShort/style.HoverDelayNormal. As the fields were added in 1.89 and expected to be left unchanged by most users, or only tweaked once during app initialization, we are exceptionally accepting the breakage.
652 - 2023/05/30 (1.89.6) - backends: renamed "imgui_impl_sdlrenderer.cpp" to "imgui_impl_sdlrenderer2.cpp" and "imgui_impl_sdlrenderer.h" to "imgui_impl_sdlrenderer2.h". This is in prevision for the future release of SDL3.
653 - 2023/05/22 (1.89.6) - listbox: commented out obsolete/redirecting functions that were marked obsolete more than two years ago:
654 - ListBoxHeader() -> use BeginListBox() (note how two variants of ListBoxHeader() existed. Check commented versions in imgui.h for reference)
655 - ListBoxFooter() -> use EndListBox()
656 - 2023/05/15 (1.89.6) - clipper: commented out obsolete redirection constructor 'ImGuiListClipper(int items_count, float items_height = -1.0f)' that was marked obsolete in 1.79. Use default constructor + clipper.Begin().
657 - 2023/05/15 (1.89.6) - clipper: renamed ImGuiListClipper::ForceDisplayRangeByIndices() to ImGuiListClipper::IncludeRangeByIndices().
658 - 2023/03/14 (1.89.4) - commented out redirecting enums/functions names that were marked obsolete two years ago:
659 - ImGuiSliderFlags_ClampOnInput -> use ImGuiSliderFlags_AlwaysClamp
660 - ImGuiInputTextFlags_AlwaysInsertMode -> use ImGuiInputTextFlags_AlwaysOverwrite
661 - ImDrawList::AddBezierCurve() -> use ImDrawList::AddBezierCubic()
662 - ImDrawList::PathBezierCurveTo() -> use ImDrawList::PathBezierCubicCurveTo()
663 - 2023/03/09 (1.89.4) - renamed PushAllowKeyboardFocus()/PopAllowKeyboardFocus() to PushTabStop()/PopTabStop(). Kept inline redirection functions (will obsolete).
664 - 2023/03/09 (1.89.4) - tooltips: Added 'bool' return value to BeginTooltip() for API consistency. Please only submit contents and call EndTooltip() if BeginTooltip() returns true. In reality the function will _currently_ always return true, but further changes down the line may change this, best to clarify API sooner.
665 - 2023/02/15 (1.89.4) - moved the optional "courtesy maths operators" implementation from imgui_internal.h in imgui.h.
666 Even though we encourage using your own maths types and operators by setting up IM_VEC2_CLASS_EXTRA,
667 it has been frequently requested by people to use our own. We had an opt-in define which was
668 previously fulfilled in imgui_internal.h. It is now fulfilled in imgui.h. (#6164)
669 - OK: #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui.h" / #include "imgui_internal.h"
670 - Error: #include "imgui.h" / #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui_internal.h"
671 - 2023/02/07 (1.89.3) - backends: renamed "imgui_impl_sdl.cpp" to "imgui_impl_sdl2.cpp" and "imgui_impl_sdl.h" to "imgui_impl_sdl2.h". (#6146) This is in prevision for the future release of SDL3.
672 - 2022/10/26 (1.89) - commented out redirecting OpenPopupContextItem() which was briefly the name of OpenPopupOnItemClick() from 1.77 to 1.79.
673 - 2022/10/12 (1.89) - removed runtime patching of invalid "%f"/"%0.f" format strings for DragInt()/SliderInt(). This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details.
674 - 2022/09/26 (1.89) - renamed and merged keyboard modifiers key enums and flags into a same set. Kept inline redirection enums (will obsolete).
675 - ImGuiKey_ModCtrl and ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl
676 - ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift
677 - ImGuiKey_ModAlt and ImGuiModFlags_Alt -> ImGuiMod_Alt
678 - ImGuiKey_ModSuper and ImGuiModFlags_Super -> ImGuiMod_Super
679 the ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends.
680 the ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api only by third-party extensions.
681 exceptionally commenting out the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion and because they were not meant to be used anyway.
682 - 2022/09/20 (1.89) - ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers.
683 this will require uses of legacy backend-dependent indices to be casted, e.g.
684 - with imgui_impl_glfw: IsKeyPressed(GLFW_KEY_A) -> IsKeyPressed((ImGuiKey)GLFW_KEY_A);
685 - with imgui_impl_win32: IsKeyPressed('A') -> IsKeyPressed((ImGuiKey)'A')
686 - etc. However if you are upgrading code you might well use the better, backend-agnostic IsKeyPressed(ImGuiKey_A) now!
687 - 2022/09/12 (1.89) - removed the bizarre legacy default argument for 'TreePush(const void* ptr = NULL)', always pass a pointer value explicitly. NULL/nullptr is ok but require cast, e.g. TreePush((void*)nullptr);
688 - 2022/09/05 (1.89) - commented out redirecting functions/enums names that were marked obsolete in 1.77 and 1.78 (June 2020):
689 - DragScalar(), DragScalarN(), DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f.
690 - SliderScalar(), SliderScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f.
691 - BeginPopupContextWindow(const char*, ImGuiMouseButton, bool) -> use BeginPopupContextWindow(const char*, ImGuiPopupFlags)
692 - 2022/09/02 (1.89) - obsoleted using SetCursorPos()/SetCursorScreenPos() to extend parent window/cell boundaries.
693 this relates to when moving the cursor position beyond current boundaries WITHOUT submitting an item.
694 - previously this would make the window content size ~200x200:
695 Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End();
696 - instead, please submit an item:
697 Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End();
698 - alternative:
699 Begin(...) + Dummy(ImVec2(200,200)) + End();
700 - content size is now only extended when submitting an item!
701 - with '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will now be detected and assert.
702 - without '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will silently be fixed until we obsolete it.
703 - 2022/08/03 (1.89) - changed signature of ImageButton() function. Kept redirection function (will obsolete).
704 - added 'const char* str_id' parameter + removed 'int frame_padding = -1' parameter.
705 - old signature: bool ImageButton(ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), int frame_padding = -1, ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));
706 - used the ImTextureID value to create an ID. This was inconsistent with other functions, led to ID conflicts, and caused problems with engines using transient ImTextureID values.
707 - had a FramePadding override which was inconsistent with other functions and made the already-long signature even longer.
708 - new signature: bool ImageButton(const char* str_id, ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));
709 - requires an explicit identifier. You may still use e.g. PushID() calls and then pass an empty identifier.
710 - always uses style.FramePadding for padding, to be consistent with other buttons. You may use PushStyleVar() to alter this.
711 - 2022/07/08 (1.89) - inputs: removed io.NavInputs[] and ImGuiNavInput enum (following 1.87 changes).
712 - Official backends from 1.87+ -> no issue.
713 - Official backends from 1.60 to 1.86 -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need updating!
714 - Custom backends not writing to io.NavInputs[] -> no issue.
715 - Custom backends writing to io.NavInputs[] -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need fixing!
716 - TL;DR: Backends should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values instead of filling io.NavInput[].
717 - 2022/06/15 (1.88) - renamed IMGUI_DISABLE_METRICS_WINDOW to IMGUI_DISABLE_DEBUG_TOOLS for correctness. kept support for old define (will obsolete).
718 - 2022/05/03 (1.88) - backends: osx: removed ImGui_ImplOSX_HandleEvent() from backend API in favor of backend automatically handling event capture. All ImGui_ImplOSX_HandleEvent() calls should be removed as they are now unnecessary.
719 - 2022/04/05 (1.88) - inputs: renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete). This was never used in public API functions but technically present in imgui.h and ImGuiIO.
720 - 2022/01/20 (1.87) - inputs: reworded gamepad IO.
721 - Backend writing to io.NavInputs[] -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values.
722 - 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic operators (+,+-,*,/) when inputting text. This doesn't break any api/code but a feature that used to be accessible by end-users (which seemingly no one used).
723 - 2022/01/17 (1.87) - inputs: reworked mouse IO.
724 - Backend writing to io.MousePos -> backend should call io.AddMousePosEvent()
725 - Backend writing to io.MouseDown[] -> backend should call io.AddMouseButtonEvent()
726 - Backend writing to io.MouseWheel -> backend should call io.AddMouseWheelEvent()
727 - Backend writing to io.MouseHoveredViewport -> backend should call io.AddMouseViewportEvent() [Docking branch w/ multi-viewports only]
728 note: for all calls to IO new functions, the Dear ImGui context should be bound/current.
729 read https://github.com/ocornut/imgui/issues/4921 for details.
730 - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(), ImGui::IsKeyDown(). Removed GetKeyIndex(), now unnecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details.
731 - IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX)
732 - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX)
733 - Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent() (+ call io.SetKeyEventNativeData() if you want legacy user code to still function with legacy key codes).
734 - Backend writing to io.KeyCtrl, io.KeyShift.. -> backend should call io.AddKeyEvent() with ImGuiMod_XXX values. *IF YOU PULLED CODE BETWEEN 2021/01/10 and 2021/01/27: We used to have a io.AddKeyModsEvent() function which was now replaced by io.AddKeyEvent() with ImGuiMod_XXX values.*
735 - one case won't work with backward compatibility: if your custom backend used ImGuiKey as mock native indices (e.g. "io.KeyMap[ImGuiKey_A] = ImGuiKey_A") because those values are now larger than the legacy KeyDown[] array. Will assert.
736 - inputs: added ImGuiKey_ModCtrl/ImGuiKey_ModShift/ImGuiKey_ModAlt/ImGuiKey_ModSuper values to submit keyboard modifiers using io.AddKeyEvent(), instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper.
737 - 2022/01/05 (1.87) - inputs: renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum.
738 - 2022/01/05 (1.87) - removed io.ImeSetInputScreenPosFn() in favor of more flexible io.SetPlatformImeDataFn(). Removed 'void* io.ImeWindowHandle' in favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'.
739 - 2022/01/01 (1.87) - commented out redirecting functions/enums names that were marked obsolete in 1.69, 1.70, 1.71, 1.72 (March-July 2019)
740 - ImGui::SetNextTreeNodeOpen() -> use ImGui::SetNextItemOpen()
741 - ImGui::GetContentRegionAvailWidth() -> use ImGui::GetContentRegionAvail().x
742 - ImGui::TreeAdvanceToLabelPos() -> use ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetTreeNodeToLabelSpacing());
743 - ImFontAtlas::CustomRect -> use ImFontAtlasCustomRect
744 - ImGuiColorEditFlags_RGB/HSV/HEX -> use ImGuiColorEditFlags_DisplayRGB/HSV/Hex
745 - 2021/12/20 (1.86) - backends: removed obsolete Marmalade backend (imgui_impl_marmalade.cpp) + example. Find last supported version at https://github.com/ocornut/imgui/wiki/Bindings
746 - 2021/11/04 (1.86) - removed CalcListClipping() function. Prefer using ImGuiListClipper which can return non-contiguous ranges. Please open an issue if you think you really need this function.
747 - 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inline redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead for generally 'GetContentRegionAvail().x' is more useful.
748 - 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019):
749 - ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList()
750 - ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBuilder
751 - 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID().
752 - if you are using official backends from the source tree: you have nothing to do.
753 - if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID().
754 - 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect() to use ImDrawFlags instead of ImDrawCornersFlags.
755 - ImDrawCornerFlags_TopLeft -> use ImDrawFlags_RoundCornersTopLeft
756 - ImDrawCornerFlags_BotRight -> use ImDrawFlags_RoundCornersBottomRight
757 - ImDrawCornerFlags_None -> use ImDrawFlags_RoundCornersNone etc.
758 flags now sanely defaults to 0 instead of 0x0F, consistent with all other flags in the API.
759 breaking: the default with rounding > 0.0f is now "round all corners" vs old implicit "round no corners":
760 - rounding == 0.0f + flags == 0 --> meant no rounding --> unchanged (common use)
761 - rounding > 0.0f + flags != 0 --> meant rounding --> unchanged (common use)
762 - rounding == 0.0f + flags != 0 --> meant no rounding --> unchanged (unlikely use)
763 - rounding > 0.0f + flags == 0 --> meant no rounding --> BREAKING (unlikely use): will now round all corners --> use ImDrawFlags_RoundCornersNone or rounding == 0.0f.
764 this ONLY matters for hard coded use of 0 + rounding > 0.0f. Use of named ImDrawFlags_RoundCornersNone (new) or ImDrawCornerFlags_None (old) are ok.
765 the old ImDrawCornersFlags used awkward default values of ~0 or 0xF (4 lower bits set) to signify "round all corners" and we sometimes encouraged using them as shortcuts.
766 legacy path still support use of hard coded ~0 or any value from 0x1 or 0xF. They will behave the same with legacy paths enabled (will assert otherwise).
767 - 2021/03/11 (1.82) - removed redirecting functions/enums names that were marked obsolete in 1.66 (September 2018):
768 - ImGui::SetScrollHere() -> use ImGui::SetScrollHereY()
769 - 2021/03/11 (1.82) - clarified that ImDrawList::PathArcTo(), ImDrawList::PathArcToFast() won't render with radius < 0.0f. Previously it sorts of accidentally worked but would generally lead to counter-clockwise paths and have an effect on anti-aliasing.
770 - 2021/03/10 (1.82) - upgraded ImDrawList::AddPolyline() and PathStroke() "bool closed" parameter to "ImDrawFlags flags". The matching ImDrawFlags_Closed value is guaranteed to always stay == 1 in the future.
771 - 2021/02/22 (1.82) - (*undone in 1.84*) win32+mingw: Re-enabled IME functions by default even under MinGW. In July 2016, issue #738 had me incorrectly disable those default functions for MinGW. MinGW users should: either link with -limm32, either set their imconfig file with '#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS'.
772 - 2021/02/17 (1.82) - renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as the meaning of the value changed.
773 - 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete).
774 - removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete).
775 - renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete).
776 - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags.
777 - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags.
778 - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API.
779 - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018):
780 - ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit().
781 - ImGuiCol_ModalWindowDarkening -> use ImGuiCol_ModalWindowDimBg
782 - ImGuiInputTextCallback -> use ImGuiTextEditCallback
783 - ImGuiInputTextCallbackData -> use ImGuiTextEditCallbackData
784 - 2020/12/21 (1.80) - renamed ImDrawList::AddBezierCurve() to AddBezierCubic(), and PathBezierCurveTo() to PathBezierCubicCurveTo(). Kept inline redirection function (will obsolete).
785 - 2020/12/04 (1.80) - added imgui_tables.cpp file! Manually constructed project files will need the new file added!
786 - 2020/11/18 (1.80) - renamed undocumented/internals ImGuiColumnsFlags_* to ImGuiOldColumnFlags_* in prevision of incoming Tables API.
787 - 2020/11/03 (1.80) - renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply to other data structures
788 - 2020/10/14 (1.80) - backends: moved all backends files (imgui_impl_XXXX.cpp, imgui_impl_XXXX.h) from examples/ to backends/.
789 - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.60 (April 2018):
790 - io.RenderDrawListsFn pointer -> use ImGui::GetDrawData() value and call the render function of your backend
791 - ImGui::IsAnyWindowFocused() -> use ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)
792 - ImGui::IsAnyWindowHovered() -> use ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
793 - ImGuiStyleVar_Count_ -> use ImGuiStyleVar_COUNT
794 - ImGuiMouseCursor_Count_ -> use ImGuiMouseCursor_COUNT
795 - removed redirecting functions names that were marked obsolete in 1.61 (May 2018):
796 - InputFloat (... int decimal_precision ...) -> use InputFloat (... const char* format ...) with format = "%.Xf" where X is your value for decimal_precision.
797 - same for InputFloat2()/InputFloat3()/InputFloat4() variants taking a `int decimal_precision` parameter.
798 - 2020/10/05 (1.79) - removed ImGuiListClipper: Renamed constructor parameters which created an ambiguous alternative to using the ImGuiListClipper::Begin() function, with misleading edge cases (note: imgui_memory_editor <0.40 from imgui_club/ used this old clipper API. Update your copy if needed).
799 - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently).
800 - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton.
801 - 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory.
802 - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on an item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result.
803 - 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now!
804 - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar().
805 replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags).
806 worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions:
807 - if you omitted the 'power' parameter (likely!), you are not affected.
808 - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct.
809 - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f.
810 see https://github.com/ocornut/imgui/issues/3361 for all details.
811 kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version was removed directly as they were most unlikely ever used.
812 for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`.
813 - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime.
814 - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems.
815 - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79]
816 - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017.
817 - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular().
818 - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more.
819 - 2019/12/17 (1.75) - [undid this change in 1.76] made Columns() limited to 64 columns by asserting above that limit. While the current code technically supports it, future code may not so we're putting the restriction ahead.
820 - 2019/12/13 (1.75) - [imgui_internal.h] changed ImRect() default constructor initializes all fields to 0.0f instead of (FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX). If you used ImRect::Add() to create bounding boxes by adding multiple points into it, you may need to fix your initial value.
821 - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017):
822 - ShowTestWindow() -> use ShowDemoWindow()
823 - IsRootWindowFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow)
824 - IsRootWindowOrAnyChildFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)
825 - SetNextWindowContentWidth(w) -> use SetNextWindowContentSize(ImVec2(w, 0.0f)
826 - GetItemsLineHeightWithSpacing() -> use GetFrameHeightWithSpacing()
827 - ImGuiCol_ChildWindowBg -> use ImGuiCol_ChildBg
828 - ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding
829 - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap
830 - IMGUI_DISABLE_TEST_WINDOWS -> use IMGUI_DISABLE_DEMO_WINDOWS
831 - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was vaguely documented and rarely if ever used). Instead, we added an explicit PrimUnreserve() API.
832 - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it).
833 - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert.
834 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency.
835 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency.
836 - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017):
837 - Begin() [old 5 args version] -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed
838 - IsRootWindowOrAnyChildHovered() -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows)
839 - AlignFirstTextHeightToWidgets() -> use AlignTextToFramePadding()
840 - SetNextWindowPosCenter() -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f)
841 - ImFont::Glyph -> use ImFontGlyph
842 - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function.
843 if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix.
844 The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay).
845 If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you.
846 - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete).
847 - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete).
848 - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names, or see how they were implemented until 1.71.
849 - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have
850 overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering.
851 This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows.
852 Please reach out if you are affected.
853 - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).
854 - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c).
855 - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now.
856 - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete).
857 - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete).
858 - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete).
859 - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrarily small value!
860 - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already).
861 - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
862 - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete).
863 - 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects.
864 - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags.
865 - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.
866 - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete).
867 - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h.
868 If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths.
869 - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427)
870 - 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp.
871 NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED.
872 Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions.
873 - 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent).
874 - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete).
875 - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly).
876 - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature.
877 - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency.
878 - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.
879 - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).
880 - 2018/06/08 (1.62) - examples: the imgui_impl_XXX files have been split to separate platform (Win32, GLFW, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.).
881 old backends will still work as is, however prefer using the separated backends as they will be updated to support multi-viewports.
882 when adopting new backends follow the main.cpp code of your preferred examples/ folder to know which functions to call.
883 in particular, note that old backends called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function.
884 - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.
885 - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
886 - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more.
887 If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.
888 To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code.
889 If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to help you find them.
890 - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format",
891 consistent with other functions. Kept redirection functions (will obsolete).
892 - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value.
893 - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some backend ahead of merging the Nav branch).
894 - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.
895 - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically.
896 - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
897 - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment.
898 - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display.
899 - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
900 - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
901 - removed Shutdown() function, as DestroyContext() serve this purpose.
902 - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.
903 - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
904 - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
905 - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths.
906 - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
907 - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
908 - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
909 - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side.
910 - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
911 - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags
912 - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame.
913 - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set.
914 - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
915 - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
916 - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
917 - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
918 - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
919 - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed.
920 - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up.
921 Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions.
922 - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
923 - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
924 - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
925 - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
926 - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency.
927 - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it.
928 - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details.
929 removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
930 IsItemHoveredRect() --> IsItemHovered(ImGuiHoveredFlags_RectOnly)
931 IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
932 IsMouseHoveringWindow() --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior]
933 - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
934 - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
935 - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete).
936 - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete).
937 - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your backend if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)".
938 - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
939 - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
940 - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
941 - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
942 - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicitly to fix.
943 - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type.
944 - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely.
945 - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete).
946 - 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete).
947 - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
948 - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu.
949 - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options.
950 - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0))'
951 - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
952 - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
953 - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
954 - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetID() and use it instead of passing string to BeginChild().
955 - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
956 - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc.
957 - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully, breakage should be minimal.
958 - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
959 If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.
960 This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color:
961 ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); }
962 If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color.
963 - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
964 - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
965 - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen).
966 - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer.
967 - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref GitHub issue #337).
968 - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337)
969 - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
970 - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert.
971 - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you.
972 - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
973 - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
974 - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
975 GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side.
976 GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out!
977 - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
978 - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project.
979 - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason
980 - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure.
981 you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
982 - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost.
983 this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
984 - if you are using a vanilla copy of one of the imgui_impl_XXX.cpp provided in the example, you just need to update your copy and you can ignore the rest.
985 - the signature of the io.RenderDrawListsFn handler has changed!
986 old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
987 new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
988 parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
989 ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
990 ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
991 - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer.
992 - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering!
993 - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
994 - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
995 - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
996 - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount.
997 - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence
998 - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely used. Sorry!
999 - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
1000 - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
1001 - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons.
1002 - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened.
1003 - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
1004 - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
1005 - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
1006 - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
1007 - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
1008 - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
1009 - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
1010 - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
1011 - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
1012 - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
1013 - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
1014 - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
1015 - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
1016 - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
1017 - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
1018 - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
1019 - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
1020 - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
1021 - old: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..];
1022 - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->SetTexID(YourTexIdentifier);
1023 you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation.
1024 - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to call io.Fonts->SetTexID()
1025 - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
1026 - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
1027 - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
1028 - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
1029 - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
1030 - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
1031 - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly)
1032 - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
1033 - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
1034 - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
1035 - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
1036 - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
1037 - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
1038
1039
1040 FREQUENTLY ASKED QUESTIONS (FAQ)
1041 ================================
1042
1043 Read all answers online:
1044 https://www.dearimgui.com/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url)
1045 Read all answers locally (with a text editor or ideally a Markdown viewer):
1046 docs/FAQ.md
1047 Some answers are copied down here to facilitate searching in code.
1048
1049 Q&A: Basics
1050 ===========
1051
1052 Q: Where is the documentation?
1053 A: This library is poorly documented at the moment and expects the user to be acquainted with C/C++.
1054 - Run the examples/ applications and explore them.
1055 - Read Getting Started (https://github.com/ocornut/imgui/wiki/Getting-Started) guide.
1056 - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
1057 - The demo covers most features of Dear ImGui, so you can read the code and see its output.
1058 - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
1059 - 20+ standalone example applications using e.g. OpenGL/DirectX are provided in the
1060 examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
1061 - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links.
1062 - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful.
1063 - Your programming IDE is your friend, find the type or function declaration to find comments
1064 associated with it.
1065
1066 Q: What is this library called?
1067 Q: Which version should I get?
1068 >> This library is called "Dear ImGui", please don't call it "ImGui" :)
1069 >> See https://www.dearimgui.com/faq for details.
1070
1071 Q&A: Integration
1072 ================
1073
1074 Q: How to get started?
1075 A: Read https://github.com/ocornut/imgui/wiki/Getting-Started. Read 'PROGRAMMER GUIDE' above. Read examples/README.txt.
1076
1077 Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?
1078 A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
1079 >> See https://www.dearimgui.com/faq for a fully detailed answer. You really want to read this.
1080
1081 Q. How can I enable keyboard or gamepad controls?
1082 Q: How can I use this on a machine without mouse, keyboard or screen? (input share, remote display)
1083 Q: I integrated Dear ImGui in my engine and little squares are showing instead of text...
1084 Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...
1085 Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...
1086 >> See https://www.dearimgui.com/faq
1087
1088 Q&A: Usage
1089 ----------
1090
1091 Q: About the ID Stack system..
1092 - Why is my widget not reacting when I click on it?
1093 - How can I have widgets with an empty label?
1094 - How can I have multiple widgets with the same label?
1095 - How can I have multiple windows with the same label?
1096 Q: How can I display an image? What is ImTextureID, how does it work?
1097 Q: How can I use my own math types instead of ImVec2?
1098 Q: How can I interact with standard C++ types (such as std::string and std::vector)?
1099 Q: How can I display custom shapes? (using low-level ImDrawList API)
1100 >> See https://www.dearimgui.com/faq
1101
1102 Q&A: Fonts, Text
1103 ================
1104
1105 Q: How should I handle DPI in my application?
1106 Q: How can I load a different font than the default?
1107 Q: How can I easily use icons in my application?
1108 Q: How can I load multiple fonts?
1109 Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
1110 >> See https://www.dearimgui.com/faq and https://github.com/ocornut/imgui/blob/master/docs/FONTS.md
1111
1112 Q&A: Concerns
1113 =============
1114
1115 Q: Who uses Dear ImGui?
1116 Q: Can you create elaborate/serious tools with Dear ImGui?
1117 Q: Can you reskin the look of Dear ImGui?
1118 Q: Why using C++ (as opposed to C)?
1119 >> See https://www.dearimgui.com/faq
1120
1121 Q&A: Community
1122 ==============
1123
1124 Q: How can I help?
1125 A: - Businesses: please reach out to "omar AT dearimgui DOT com" if you work in a place using Dear ImGui!
1126 We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts.
1127 This is among the most useful thing you can do for Dear ImGui. With increased funding, we sustain and grow work on this project.
1128 >>> See https://github.com/ocornut/imgui/wiki/Funding
1129 - Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine.
1130 - If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, and see how you want to help and can help!
1131 - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
1132 You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers.
1133 But even without visuals, disclosing your use of dear imgui helps the library grow credibility, and help other teams and programmers with taking decisions.
1134 - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on GitHub or privately).
1135
1136*/
1137
1138//-------------------------------------------------------------------------
1139// [SECTION] INCLUDES
1140//-------------------------------------------------------------------------
1141
1142#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
1143#define _CRT_SECURE_NO_WARNINGS
1144#endif
1145
1146#ifndef IMGUI_DEFINE_MATH_OPERATORS
1147#define IMGUI_DEFINE_MATH_OPERATORS
1148#endif
1149
1150#include "imgui.h"
1151#ifndef IMGUI_DISABLE
1152#include "imgui_internal.h"
1153
1154// System includes
1155#include <stdio.h> // vsnprintf, sscanf, printf
1156#include <stdint.h> // intptr_t
1157
1158// [Windows] On non-Visual Studio compilers, we default to IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS unless explicitly enabled
1159#if defined(_WIN32) && !defined(_MSC_VER) && !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
1160#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
1161#endif
1162
1163// [Windows] OS specific includes (optional)
1164#if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && defined(IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
1165#define IMGUI_DISABLE_WIN32_FUNCTIONS
1166#endif
1167#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
1168#ifndef WIN32_LEAN_AND_MEAN
1169#define WIN32_LEAN_AND_MEAN
1170#endif
1171#ifndef NOMINMAX
1172#define NOMINMAX
1173#endif
1174#ifndef __MINGW32__
1175#include <Windows.h> // _wfopen, OpenClipboard
1176#else
1177#include <windows.h>
1178#endif
1179#if defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_APP) && WINAPI_FAMILY == WINAPI_FAMILY_APP) || (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES))
1180// The UWP and GDK Win32 API subsets don't support clipboard nor IME functions
1181#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
1182#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
1183#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
1184#endif
1185#endif
1186
1187// [Apple] OS specific includes
1188#if defined(__APPLE__)
1189#include <TargetConditionals.h>
1190#endif
1191
1192// Visual Studio warnings
1193#ifdef _MSC_VER
1194#pragma warning (disable: 4127) // condition expression is constant
1195#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
1196#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later
1197#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types
1198#endif
1199#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to an 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
1200#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6).
1201#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
1202#endif
1203
1204// Clang/GCC warnings with -Weverything
1205#if defined(__clang__)
1206#if __has_warning("-Wunknown-warning-option")
1207#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
1208#endif
1209#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
1210#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
1211#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
1212#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int'
1213#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
1214#pragma clang diagnostic ignored "-Wformat-pedantic" // warning: format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic.
1215#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
1216#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is.
1217#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
1218#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type 'int'
1219#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
1220#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
1221#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
1222#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
1223#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
1224#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label
1225#elif defined(__GNUC__)
1226// We disable -Wpragmas because GCC doesn't provide a has_warning equivalent and some forks/patches may not follow the warning/version association.
1227#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
1228#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
1229#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
1230#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
1231#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*'
1232#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
1233#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
1234#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
1235#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
1236#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
1237#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers
1238#endif
1239
1240// Debug options
1241#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Hold CTRL to display for all candidates. CTRL+Arrow to change last direction.
1242#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window
1243
1244// Default font size if unspecified in both style.FontSizeBase and AddFontXXX() calls.
1245static const float FONT_DEFAULT_SIZE = 20.0f;
1246
1247// When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch.
1248static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in
1249static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear
1250static const float NAV_ACTIVATE_HIGHLIGHT_TIMER = 0.10f; // Time to highlight an item activated by a shortcut.
1251static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
1252static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved.
1253
1254// Tooltip offset
1255static const ImVec2 TOOLTIP_DEFAULT_OFFSET_MOUSE = ImVec2(16, 10); // Multiplied by g.Style.MouseCursorScale
1256static const ImVec2 TOOLTIP_DEFAULT_OFFSET_TOUCH = ImVec2(0, -20); // Multiplied by g.Style.MouseCursorScale
1257static const ImVec2 TOOLTIP_DEFAULT_PIVOT_TOUCH = ImVec2(0.5f, 1.0f); // Multiplied by g.Style.MouseCursorScale
1258
1259// Docking
1260static const float DOCKING_TRANSPARENT_PAYLOAD_ALPHA = 0.50f; // For use with io.ConfigDockingTransparentPayload. Apply to Viewport _or_ WindowBg in host viewport.
1261
1262//-------------------------------------------------------------------------
1263// [SECTION] FORWARD DECLARATIONS
1264//-------------------------------------------------------------------------
1265
1266static void SetCurrentWindow(ImGuiWindow* window);
1267static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags);
1269
1270static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
1271
1272// Settings
1274static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
1275static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
1278
1279// Platform Dependents default implementation for ImGuiPlatformIO functions
1281static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const char* text);
1283static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext* ctx, const char* path);
1284
1285namespace ImGui
1286{
1287// Item
1288static void ItemHandleShortcut(ImGuiID id);
1289
1290// Window Focus
1291static int FindWindowFocusIndex(ImGuiWindow* window);
1292static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags);
1293
1294// Navigation
1295static void NavUpdate();
1296static void NavUpdateWindowing();
1297static void NavUpdateWindowingApplyFocus(ImGuiWindow* window);
1298static void NavUpdateWindowingOverlay();
1299static void NavUpdateCancelRequest();
1300static void NavUpdateCreateMoveRequest();
1301static void NavUpdateCreateTabbingRequest();
1302static float NavUpdatePageUpPageDown();
1303static inline void NavUpdateAnyRequestFlag();
1304static void NavUpdateCreateWrappingRequest();
1305static void NavEndFrame();
1306static bool NavScoreItem(ImGuiNavItemData* result);
1307static void NavApplyItemToResult(ImGuiNavItemData* result);
1308static void NavProcessItem();
1309static void NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags);
1312static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
1314static void NavRestoreLayer(ImGuiNavLayer layer);
1315
1316// Error Checking and Debug Tools
1317static void ErrorCheckNewFrameSanityChecks();
1318static void ErrorCheckEndFrameSanityChecks();
1319#ifndef IMGUI_DISABLE_DEBUG_TOOLS
1320static void UpdateDebugToolItemPicker();
1321static void UpdateDebugToolStackQueries();
1322static void UpdateDebugToolFlashStyleColor();
1323#endif
1324
1325// Inputs
1326static void UpdateKeyboardInputs();
1327static void UpdateMouseInputs();
1328static void UpdateMouseWheel();
1330
1331// Misc
1332static void UpdateFontsNewFrame();
1333static void UpdateFontsEndFrame();
1334static void UpdateTexturesNewFrame();
1335static void UpdateTexturesEndFrame();
1336static void UpdateSettings();
1337static int UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_hovered, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect);
1338static void RenderWindowOuterBorders(ImGuiWindow* window);
1339static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
1340static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
1341static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col);
1342static void RenderDimmedBackgrounds();
1343static void SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect);
1344static void SetLastItemDataForChildWindowItem(ImGuiWindow* window, const ImRect& rect);
1345
1346// Viewports
1347const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbitrary constant instead of e.g. ImHashStr("ViewportDefault", 0); so it's easier to spot in the debugger. The exact value doesn't matter.
1348static ImGuiViewportP* AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImVec2& platform_pos, const ImVec2& size, ImGuiViewportFlags flags);
1349static void DestroyViewport(ImGuiViewportP* viewport);
1350static void UpdateViewportsNewFrame();
1351static void UpdateViewportsEndFrame();
1352static void WindowSelectViewport(ImGuiWindow* window);
1353static void WindowSyncOwnedViewport(ImGuiWindow* window, ImGuiWindow* parent_window_in_stack);
1354static bool UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* host_viewport);
1356static bool GetWindowAlwaysWantOwnViewport(ImGuiWindow* window);
1357static int FindPlatformMonitorForPos(const ImVec2& pos);
1358static int FindPlatformMonitorForRect(const ImRect& r);
1359static void UpdateViewportPlatformMonitor(ImGuiViewportP* viewport);
1360
1361}
1362
1363//-----------------------------------------------------------------------------
1364// [SECTION] CONTEXT AND MEMORY ALLOCATORS
1365//-----------------------------------------------------------------------------
1366
1367// DLL users:
1368// - Heaps and globals are not shared across DLL boundaries!
1369// - You will need to call SetCurrentContext() + SetAllocatorFunctions() for each static/DLL boundary you are calling from.
1370// - Same applies for hot-reloading mechanisms that are reliant on reloading DLL (note that many hot-reloading mechanisms work without DLL).
1371// - Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
1372// - Confused? In a debugger: add GImGui to your watch window and notice how its value changes depending on your current location (which DLL boundary you are in).
1373
1374// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL.
1375// - ImGui::CreateContext() will automatically set this pointer if it is NULL.
1376// Change to a different context by calling ImGui::SetCurrentContext().
1377// - Important: Dear ImGui functions are not thread-safe because of this pointer.
1378// If you want thread-safety to allow N threads to access N different contexts:
1379// - Change this variable to use thread local storage so each thread can refer to a different context, in your imconfig.h:
1380// struct ImGuiContext;
1381// extern thread_local ImGuiContext* MyImGuiTLS;
1382// #define GImGui MyImGuiTLS
1383// And then define MyImGuiTLS in one of your cpp files. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword.
1384// - Future development aims to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
1385// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from a different namespace.
1386// - DLL users: read comments above.
1387#ifndef GImGui
1389#endif
1390
1391// Memory Allocator functions. Use SetAllocatorFunctions() to change them.
1392// - You probably don't want to modify that mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.
1393// - DLL users: read comments above.
1394#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
1395static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); }
1396static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); }
1397#else
1398static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; }
1399static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); }
1400#endif
1403static void* GImAllocatorUserData = NULL;
1404
1405//-----------------------------------------------------------------------------
1406// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO, ImGuiPlatformIO)
1407//-----------------------------------------------------------------------------
1408
1410{
1411 FontSizeBase = 0.0f; // Will default to io.Fonts->Fonts[0] on first frame.
1412 FontScaleMain = 1.0f; // Main scale factor. May be set by application once, or exposed to end-user.
1413 FontScaleDpi = 1.0f; // Additional scale factor from viewport/monitor contents scale. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI.
1414
1415 Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui.
1416 DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha.
1417 WindowPadding = ImVec2(8,8); // Padding within a window
1418 WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
1419 WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1420 WindowBorderHoverPadding = 4.0f; // Hit-testing extent outside/inside resizing border. Also extend determination of hovered window. Generally meaningfully larger than WindowBorderSize to make it easy to reach borders.
1421 WindowMinSize = ImVec2(32,32); // Minimum window size
1422 WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
1423 WindowMenuButtonPosition = ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
1424 ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
1425 ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1426 PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
1427 PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1428 FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets)
1429 FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
1430 FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
1431 ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
1432 ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
1433 CellPadding = ImVec2(4,2); // Padding within a table cell. Cellpadding.x is locked for entire table. CellPadding.y may be altered between different rows.
1434 TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
1435 IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
1436 ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
1437 ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
1438 ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
1439 GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar
1440 GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
1441 LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
1442 ImageBorderSize = 0.0f; // Thickness of border around tabs.
1443 TabRounding = 5.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
1444 TabBorderSize = 0.0f; // Thickness of border around tabs.
1445 TabCloseButtonMinWidthSelected = -1.0f; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width.
1446 TabCloseButtonMinWidthUnselected = 0.0f; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected.
1447 TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
1448 TabBarOverlineSize = 1.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar.
1449 TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees).
1450 TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell
1452 TreeLinesSize = 1.0f; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines.
1453 TreeLinesRounding = 0.0f; // Radius of lines connecting child nodes to the vertical line.
1454 ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
1455 ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
1456 SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
1457 SeparatorTextBorderSize = 3.0f; // Thickness of border in SeparatorText()
1458 SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
1459 SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
1460 DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
1461 DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
1462 DockingSeparatorSize = 2.0f; // Thickness of resizing border between docked windows
1463 MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
1464 AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
1465 AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering).
1466 AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).
1467 CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
1468 CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
1469
1470 // Behaviors
1471 HoverStationaryDelay = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary.
1472 HoverDelayShort = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay.
1473 HoverDelayNormal = 0.40f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). "
1474 HoverFlagsForTooltipMouse = ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_AllowWhenDisabled; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse.
1475 HoverFlagsForTooltipNav = ImGuiHoveredFlags_NoSharedDelay | ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_AllowWhenDisabled; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad.
1476
1477 // [Internal]
1478 _MainScale = 1.0f;
1480
1481 // Default theme
1483}
1484
1485
1486// Scale all spacing/padding/thickness values. Do not scale fonts.
1487// Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times.
1488void ImGuiStyle::ScaleAllSizes(float scale_factor)
1489{
1490 _MainScale *= scale_factor;
1491 WindowPadding = ImTrunc(WindowPadding * scale_factor);
1492 WindowRounding = ImTrunc(WindowRounding * scale_factor);
1493 WindowMinSize = ImTrunc(WindowMinSize * scale_factor);
1495 ChildRounding = ImTrunc(ChildRounding * scale_factor);
1496 PopupRounding = ImTrunc(PopupRounding * scale_factor);
1497 FramePadding = ImTrunc(FramePadding * scale_factor);
1498 FrameRounding = ImTrunc(FrameRounding * scale_factor);
1499 ItemSpacing = ImTrunc(ItemSpacing * scale_factor);
1500 ItemInnerSpacing = ImTrunc(ItemInnerSpacing * scale_factor);
1501 CellPadding = ImTrunc(CellPadding * scale_factor);
1503 IndentSpacing = ImTrunc(IndentSpacing * scale_factor);
1505 ScrollbarSize = ImTrunc(ScrollbarSize * scale_factor);
1507 GrabMinSize = ImTrunc(GrabMinSize * scale_factor);
1508 GrabRounding = ImTrunc(GrabRounding * scale_factor);
1510 ImageBorderSize = ImTrunc(ImageBorderSize * scale_factor);
1511 TabRounding = ImTrunc(TabRounding * scale_factor);
1520 MouseCursorScale = ImTrunc(MouseCursorScale * scale_factor);
1521}
1522
1524{
1525 // Most fields are initialized with zero
1526 memset(this, 0, sizeof(*this));
1528
1529 // Settings
1532 DisplaySize = ImVec2(-1.0f, -1.0f);
1533 DeltaTime = 1.0f / 60.0f;
1534 IniSavingRate = 5.0f;
1535 IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables).
1536 LogFilename = "imgui_log.txt";
1537 UserData = NULL;
1538
1539 Fonts = NULL;
1540 FontDefault = NULL;
1541 FontAllowUserScaling = false;
1542#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1543 FontGlobalScale = 1.0f; // Use style.FontScaleMain instead!
1544#endif
1545 DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
1546
1547 // Keyboard/Gamepad Navigation options
1555
1556 // Docking options (when ImGuiConfigFlags_DockingEnable is set)
1557 ConfigDockingNoSplit = false;
1558 ConfigDockingWithShift = false;
1561
1562 // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set)
1567
1568 // Miscellaneous options
1569 MouseDrawCursor = false;
1570#ifdef __APPLE__
1571 ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag
1572#else
1573 ConfigMacOSXBehaviors = false;
1574#endif
1589
1590 ConfigErrorRecovery = true;
1594
1595 // Inputs Behaviors
1596 MouseDoubleClickTime = 0.30f;
1598 MouseDragThreshold = 6.0f;
1599 KeyRepeatDelay = 0.275f;
1600 KeyRepeatRate = 0.050f;
1601
1602 // Platform Functions
1603 // Note: Initialize() will setup default clipboard/ime handlers.
1606
1607 // Input (NB: we already have memset zero the entire structure!)
1608 MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
1609 MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
1611 for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
1612 for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; }
1613 AppAcceptingEvents = true;
1614}
1615
1616// Pass in translated ASCII characters for text input.
1617// - with glfw you can get those from the callback set in glfwSetCharCallback()
1618// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
1619// FIXME: Should in theory be called "AddCharacterEvent()" to be consistent with new API
1620void ImGuiIO::AddInputCharacter(unsigned int c)
1621{
1622 IM_ASSERT(Ctx != NULL);
1623 ImGuiContext& g = *Ctx;
1624 if (c == 0 || !AppAcceptingEvents)
1625 return;
1626
1631 e.Text.Char = c;
1633}
1634
1635// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so
1636// we should save the high surrogate.
1638{
1639 if ((c == 0 && InputQueueSurrogate == 0) || !AppAcceptingEvents)
1640 return;
1641
1642 if ((c & 0xFC00) == 0xD800) // High surrogate, must save
1643 {
1644 if (InputQueueSurrogate != 0)
1647 return;
1648 }
1649
1650 ImWchar cp = c;
1651 if (InputQueueSurrogate != 0)
1652 {
1653 if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
1654 {
1656 }
1657 else
1658 {
1659#if IM_UNICODE_CODEPOINT_MAX == 0xFFFF
1660 cp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWchar
1661#else
1662 cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);
1663#endif
1664 }
1665
1667 }
1668 AddInputCharacter((unsigned)cp);
1669}
1670
1671void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
1672{
1673 if (!AppAcceptingEvents)
1674 return;
1675 while (*utf8_chars != 0)
1676 {
1677 unsigned int c = 0;
1678 utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
1680 }
1681}
1682
1683// Clear all incoming events.
1685{
1686 IM_ASSERT(Ctx != NULL);
1687 ImGuiContext& g = *Ctx;
1689}
1690
1691// Clear current keyboard/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.
1693{
1694 ImGuiContext& g = *Ctx;
1695 for (int key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key++)
1696 {
1697 if (ImGui::IsMouseKey((ImGuiKey)key))
1698 continue;
1699 ImGuiKeyData* key_data = &g.IO.KeysData[key - ImGuiKey_NamedKey_BEGIN];
1700 key_data->Down = false;
1701 key_data->DownDuration = -1.0f;
1702 key_data->DownDurationPrev = -1.0f;
1703 }
1704 KeyCtrl = KeyShift = KeyAlt = KeySuper = false;
1706 InputQueueCharacters.resize(0); // Behavior of old ClearInputCharacters().
1707}
1708
1710{
1711 for (ImGuiKey key = ImGuiKey_Mouse_BEGIN; key < ImGuiKey_Mouse_END; key = (ImGuiKey)(key + 1))
1712 {
1713 ImGuiKeyData* key_data = &KeysData[key - ImGuiKey_NamedKey_BEGIN];
1714 key_data->Down = false;
1715 key_data->DownDuration = -1.0f;
1716 key_data->DownDurationPrev = -1.0f;
1717 }
1718 MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
1719 for (int n = 0; n < IM_ARRAYSIZE(MouseDown); n++)
1720 {
1721 MouseDown[n] = false;
1723 }
1724 MouseWheel = MouseWheelH = 0.0f;
1725}
1726
1727// Removed this as it is ambiguous/misleading and generally incorrect to use with the existence of a higher-level input queue.
1728// Current frame character buffer is now also cleared by ClearInputKeys().
1729#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1731{
1733}
1734#endif
1735
1737{
1738 ImGuiContext& g = *ctx;
1739 for (int n = g.InputEventsQueue.Size - 1; n >= 0; n--)
1740 {
1742 if (e->Type != type)
1743 continue;
1744 if (type == ImGuiInputEventType_Key && e->Key.Key != arg)
1745 continue;
1746 if (type == ImGuiInputEventType_MouseButton && e->MouseButton.Button != arg)
1747 continue;
1748 return e;
1749 }
1750 return NULL;
1751}
1752
1753// Queue a new key down/up event.
1754// - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character)
1755// - bool down: Is the key down? use false to signify a key release.
1756// - float analog_value: 0.0f..1.0f
1757// IMPORTANT: THIS FUNCTION AND OTHER "ADD" GRABS THE CONTEXT FROM OUR INSTANCE.
1758// WE NEED TO ENSURE THAT ALL FUNCTION CALLS ARE FULFILLING THIS, WHICH IS WHY GetKeyData() HAS AN EXPLICIT CONTEXT.
1759void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
1760{
1761 //if (e->Down) { IMGUI_DEBUG_LOG_IO("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); }
1762 IM_ASSERT(Ctx != NULL);
1763 if (key == ImGuiKey_None || !AppAcceptingEvents)
1764 return;
1765 ImGuiContext& g = *Ctx;
1766 IM_ASSERT(ImGui::IsNamedKeyOrMod(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API.
1767 IM_ASSERT(ImGui::IsAliasKey(key) == false); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events.
1768
1769 // MacOS: swap Cmd(Super) and Ctrl
1771 {
1772 if (key == ImGuiMod_Super) { key = ImGuiMod_Ctrl; }
1773 else if (key == ImGuiMod_Ctrl) { key = ImGuiMod_Super; }
1774 else if (key == ImGuiKey_LeftSuper) { key = ImGuiKey_LeftCtrl; }
1775 else if (key == ImGuiKey_RightSuper){ key = ImGuiKey_RightCtrl; }
1776 else if (key == ImGuiKey_LeftCtrl) { key = ImGuiKey_LeftSuper; }
1777 else if (key == ImGuiKey_RightCtrl) { key = ImGuiKey_RightSuper; }
1778 }
1779
1780 // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed)
1781 const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key);
1782 const ImGuiKeyData* key_data = ImGui::GetKeyData(&g, key);
1783 const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down;
1784 const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue;
1785 if (latest_key_down == down && latest_key_analog == analog_value)
1786 return;
1787
1788 // Add event
1793 e.Key.Key = key;
1794 e.Key.Down = down;
1795 e.Key.AnalogValue = analog_value;
1797}
1798
1799void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
1800{
1801 if (!AppAcceptingEvents)
1802 return;
1803 AddKeyAnalogEvent(key, down, down ? 1.0f : 0.0f);
1804}
1805
1806// [Optional] Call after AddKeyEvent().
1807// Specify native keycode, scancode + Specify index for legacy <1.87 IsKeyXXX() functions with native indices.
1808// If you are writing a backend in 2022 or don't use IsKeyXXX() with native values that are not ImGuiKey values, you can avoid calling this.
1809void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index)
1810{
1811 if (key == ImGuiKey_None)
1812 return;
1813 IM_ASSERT(ImGui::IsNamedKey(key)); // >= 512
1814 IM_ASSERT(native_legacy_index == -1 || ImGui::IsLegacyKey((ImGuiKey)native_legacy_index)); // >= 0 && <= 511
1815 IM_UNUSED(key); // Yet unused
1816 IM_UNUSED(native_keycode); // Yet unused
1817 IM_UNUSED(native_scancode); // Yet unused
1818 IM_UNUSED(native_legacy_index); // Yet unused
1819}
1820
1821// Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen.
1822void ImGuiIO::SetAppAcceptingEvents(bool accepting_events)
1823{
1824 AppAcceptingEvents = accepting_events;
1825}
1826
1827// Queue a mouse move event
1828void ImGuiIO::AddMousePosEvent(float x, float y)
1829{
1830 IM_ASSERT(Ctx != NULL);
1831 ImGuiContext& g = *Ctx;
1832 if (!AppAcceptingEvents)
1833 return;
1834
1835 // Apply same flooring as UpdateMouseInputs()
1836 ImVec2 pos((x > -FLT_MAX) ? ImFloor(x) : x, (y > -FLT_MAX) ? ImFloor(y) : y);
1837
1838 // Filter duplicate
1840 const ImVec2 latest_pos = latest_event ? ImVec2(latest_event->MousePos.PosX, latest_event->MousePos.PosY) : g.IO.MousePos;
1841 if (latest_pos.x == pos.x && latest_pos.y == pos.y)
1842 return;
1843
1848 e.MousePos.PosX = pos.x;
1849 e.MousePos.PosY = pos.y;
1852}
1853
1854void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
1855{
1856 IM_ASSERT(Ctx != NULL);
1857 ImGuiContext& g = *Ctx;
1858 IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT);
1859 if (!AppAcceptingEvents)
1860 return;
1861
1862 // On MacOS X: Convert Ctrl(Super)+Left click into Right-click: handle held button.
1863 if (ConfigMacOSXBehaviors && mouse_button == 0 && MouseCtrlLeftAsRightClick)
1864 {
1865 // Order of both statements matters: this event will still release mouse button 1
1866 mouse_button = 1;
1867 if (!down)
1869 }
1870
1871 // Filter duplicate
1872 const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MouseButton, (int)mouse_button);
1873 const bool latest_button_down = latest_event ? latest_event->MouseButton.Down : g.IO.MouseDown[mouse_button];
1874 if (latest_button_down == down)
1875 return;
1876
1877 // On MacOS X: Convert Ctrl(Super)+Left click into Right-click.
1878 // - Note that this is actual physical Ctrl which is ImGuiMod_Super for us.
1879 // - At this point we want from !down to down, so this is handling the initial press.
1880 if (ConfigMacOSXBehaviors && mouse_button == 0 && down)
1881 {
1882 const ImGuiInputEvent* latest_super_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)ImGuiMod_Super);
1883 if (latest_super_event ? latest_super_event->Key.Down : g.IO.KeySuper)
1884 {
1885 IMGUI_DEBUG_LOG_IO("[io] Super+Left Click aliased into Right Click\n");
1887 AddMouseButtonEvent(1, true); // This is just quicker to write that passing through, as we need to filter duplicate again.
1888 return;
1889 }
1890 }
1891
1896 e.MouseButton.Button = mouse_button;
1897 e.MouseButton.Down = down;
1900}
1901
1902// Queue a mouse wheel event (some mouse/API may only have a Y component)
1903void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
1904{
1905 IM_ASSERT(Ctx != NULL);
1906 ImGuiContext& g = *Ctx;
1907
1908 // Filter duplicate (unlike most events, wheel values are relative and easy to filter)
1909 if (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f))
1910 return;
1911
1916 e.MouseWheel.WheelX = wheel_x;
1917 e.MouseWheel.WheelY = wheel_y;
1920}
1921
1922// This is not a real event, the data is latched in order to be stored in actual Mouse events.
1923// This is so that duplicate events (e.g. Windows sending extraneous WM_MOUSEMOVE) gets filtered and are not leading to actual source changes.
1925{
1926 IM_ASSERT(Ctx != NULL);
1927 ImGuiContext& g = *Ctx;
1928 g.InputEventsNextMouseSource = source;
1929}
1930
1932{
1933 IM_ASSERT(Ctx != NULL);
1934 ImGuiContext& g = *Ctx;
1935 //IM_ASSERT(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport);
1936 if (!AppAcceptingEvents)
1937 return;
1938
1939 // Filter duplicate
1941 const ImGuiID latest_viewport_id = latest_event ? latest_event->MouseViewport.HoveredViewportID : g.IO.MouseHoveredViewport;
1942 if (latest_viewport_id == viewport_id)
1943 return;
1944
1948 e.MouseViewport.HoveredViewportID = viewport_id;
1950}
1951
1952void ImGuiIO::AddFocusEvent(bool focused)
1953{
1954 IM_ASSERT(Ctx != NULL);
1955 ImGuiContext& g = *Ctx;
1956
1957 // Filter duplicate
1959 const bool latest_focused = latest_event ? latest_event->AppFocused.Focused : !g.IO.AppFocusLost;
1960 if (latest_focused == focused || (ConfigDebugIgnoreFocusLoss && !focused))
1961 return;
1962
1966 e.AppFocused.Focused = focused;
1968}
1969
1971{
1972 // Most fields are initialized with zero
1973 memset(this, 0, sizeof(*this));
1975}
1976
1977//-----------------------------------------------------------------------------
1978// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
1979//-----------------------------------------------------------------------------
1980
1981ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)
1982{
1983 IM_ASSERT(num_segments > 0); // Use ImBezierCubicClosestPointCasteljau()
1984 ImVec2 p_last = p1;
1985 ImVec2 p_closest;
1986 float p_closest_dist2 = FLT_MAX;
1987 float t_step = 1.0f / (float)num_segments;
1988 for (int i_step = 1; i_step <= num_segments; i_step++)
1989 {
1990 ImVec2 p_current = ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step);
1991 ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
1992 float dist2 = ImLengthSqr(p - p_line);
1993 if (dist2 < p_closest_dist2)
1994 {
1995 p_closest = p_line;
1996 p_closest_dist2 = dist2;
1997 }
1998 p_last = p_current;
1999 }
2000 return p_closest;
2001}
2002
2003// Closely mimics PathBezierToCasteljau() in imgui_draw.cpp
2004static void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
2005{
2006 float dx = x4 - x1;
2007 float dy = y4 - y1;
2008 float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
2009 float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
2010 d2 = (d2 >= 0) ? d2 : -d2;
2011 d3 = (d3 >= 0) ? d3 : -d3;
2012 if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
2013 {
2014 ImVec2 p_current(x4, y4);
2015 ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
2016 float dist2 = ImLengthSqr(p - p_line);
2017 if (dist2 < p_closest_dist2)
2018 {
2019 p_closest = p_line;
2020 p_closest_dist2 = dist2;
2021 }
2022 p_last = p_current;
2023 }
2024 else if (level < 10)
2025 {
2026 float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f;
2027 float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f;
2028 float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f;
2029 float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f;
2030 float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f;
2031 float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
2032 ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
2033 ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
2034 }
2035}
2036
2037// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol
2038// Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically.
2039ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol)
2040{
2041 IM_ASSERT(tess_tol > 0.0f);
2042 ImVec2 p_last = p1;
2043 ImVec2 p_closest;
2044 float p_closest_dist2 = FLT_MAX;
2045 ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
2046 return p_closest;
2047}
2048
2049ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
2050{
2051 ImVec2 ap = p - a;
2052 ImVec2 ab_dir = b - a;
2053 float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
2054 if (dot < 0.0f)
2055 return a;
2056 float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
2057 if (dot > ab_len_sqr)
2058 return b;
2059 return a + ab_dir * dot / ab_len_sqr;
2060}
2061
2062bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
2063{
2064 bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
2065 bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
2066 bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
2067 return ((b1 == b2) && (b2 == b3));
2068}
2069
2070void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
2071{
2072 ImVec2 v0 = b - a;
2073 ImVec2 v1 = c - a;
2074 ImVec2 v2 = p - a;
2075 const float denom = v0.x * v1.y - v1.x * v0.y;
2076 out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
2077 out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
2078 out_u = 1.0f - out_v - out_w;
2079}
2080
2081ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
2082{
2083 ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
2084 ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
2085 ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
2086 float dist2_ab = ImLengthSqr(p - proj_ab);
2087 float dist2_bc = ImLengthSqr(p - proj_bc);
2088 float dist2_ca = ImLengthSqr(p - proj_ca);
2089 float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
2090 if (m == dist2_ab)
2091 return proj_ab;
2092 if (m == dist2_bc)
2093 return proj_bc;
2094 return proj_ca;
2095}
2096
2097//-----------------------------------------------------------------------------
2098// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
2099//-----------------------------------------------------------------------------
2100
2101// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more.
2102int ImStricmp(const char* str1, const char* str2)
2103{
2104 int d;
2105 while ((d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; }
2106 return d;
2107}
2108
2109int ImStrnicmp(const char* str1, const char* str2, size_t count)
2110{
2111 int d = 0;
2112 while (count > 0 && (d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
2113 return d;
2114}
2115
2116void ImStrncpy(char* dst, const char* src, size_t count)
2117{
2118 if (count < 1)
2119 return;
2120 if (count > 1)
2121 strncpy(dst, src, count - 1);
2122 dst[count - 1] = 0;
2123}
2124
2125char* ImStrdup(const char* str)
2126{
2127 size_t len = ImStrlen(str);
2128 void* buf = IM_ALLOC(len + 1);
2129 return (char*)memcpy(buf, (const void*)str, len + 1);
2130}
2131
2132void* ImMemdup(const void* src, size_t size)
2133{
2134 void* dst = IM_ALLOC(size);
2135 return memcpy(dst, src, size);
2136}
2137
2138char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)
2139{
2140 size_t dst_buf_size = p_dst_size ? *p_dst_size : ImStrlen(dst) + 1;
2141 size_t src_size = ImStrlen(src) + 1;
2142 if (dst_buf_size < src_size)
2143 {
2144 IM_FREE(dst);
2145 dst = (char*)IM_ALLOC(src_size);
2146 if (p_dst_size)
2147 *p_dst_size = src_size;
2148 }
2149 return (char*)memcpy(dst, (const void*)src, src_size);
2150}
2151
2152const char* ImStrchrRange(const char* str, const char* str_end, char c)
2153{
2154 const char* p = (const char*)ImMemchr(str, (int)c, str_end - str);
2155 return p;
2156}
2157
2158int ImStrlenW(const ImWchar* str)
2159{
2160 //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bit
2161 int n = 0;
2162 while (*str++) n++;
2163 return n;
2164}
2165
2166// Find end-of-line. Return pointer will point to either first \n, either str_end.
2167const char* ImStreolRange(const char* str, const char* str_end)
2168{
2169 const char* p = (const char*)ImMemchr(str, '\n', str_end - str);
2170 return p ? p : str_end;
2171}
2172
2173const char* ImStrbol(const char* buf_mid_line, const char* buf_begin) // find beginning-of-line
2174{
2175 IM_ASSERT_PARANOID(buf_mid_line >= buf_begin && buf_mid_line <= buf_begin + ImStrlen(buf_begin));
2176 while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
2177 buf_mid_line--;
2178 return buf_mid_line;
2179}
2180
2181const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
2182{
2183 if (!needle_end)
2184 needle_end = needle + ImStrlen(needle);
2185
2186 const char un0 = (char)ImToUpper(*needle);
2187 while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
2188 {
2189 if (ImToUpper(*haystack) == un0)
2190 {
2191 const char* b = needle + 1;
2192 for (const char* a = haystack + 1; b < needle_end; a++, b++)
2193 if (ImToUpper(*a) != ImToUpper(*b))
2194 break;
2195 if (b == needle_end)
2196 return haystack;
2197 }
2198 haystack++;
2199 }
2200 return NULL;
2201}
2202
2203// Trim str by offsetting contents when there's leading data + writing a \0 at the trailing position. We use this in situation where the cost is negligible.
2204void ImStrTrimBlanks(char* buf)
2205{
2206 char* p = buf;
2207 while (p[0] == ' ' || p[0] == '\t') // Leading blanks
2208 p++;
2209 char* p_start = p;
2210 while (*p != 0) // Find end of string
2211 p++;
2212 while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks
2213 p--;
2214 if (p_start != buf) // Copy memory if we had leading blanks
2215 memmove(buf, p_start, p - p_start);
2216 buf[p - p_start] = 0; // Zero terminate
2217}
2218
2219const char* ImStrSkipBlank(const char* str)
2220{
2221 while (str[0] == ' ' || str[0] == '\t')
2222 str++;
2223 return str;
2224}
2225
2226// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
2227// Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm.
2228// B) When buf==NULL vsnprintf() will return the output size.
2229#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
2230
2231// We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h)
2232// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
2233// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are
2234// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.)
2235#ifdef IMGUI_USE_STB_SPRINTF
2236#ifndef IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION
2237#define STB_SPRINTF_IMPLEMENTATION
2238#endif
2239#ifdef IMGUI_STB_SPRINTF_FILENAME
2240#include IMGUI_STB_SPRINTF_FILENAME
2241#else
2242#include "stb_sprintf.h"
2243#endif
2244#endif // #ifdef IMGUI_USE_STB_SPRINTF
2245
2246#if defined(_MSC_VER) && !defined(vsnprintf)
2247#define vsnprintf _vsnprintf
2248#endif
2249
2250int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
2251{
2252 va_list args;
2253 va_start(args, fmt);
2254#ifdef IMGUI_USE_STB_SPRINTF
2255 int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
2256#else
2257 int w = vsnprintf(buf, buf_size, fmt, args);
2258#endif
2259 va_end(args);
2260 if (buf == NULL)
2261 return w;
2262 if (w == -1 || w >= (int)buf_size)
2263 w = (int)buf_size - 1;
2264 buf[w] = 0;
2265 return w;
2266}
2267
2268int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
2269{
2270#ifdef IMGUI_USE_STB_SPRINTF
2271 int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
2272#else
2273 int w = vsnprintf(buf, buf_size, fmt, args);
2274#endif
2275 if (buf == NULL)
2276 return w;
2277 if (w == -1 || w >= (int)buf_size)
2278 w = (int)buf_size - 1;
2279 buf[w] = 0;
2280 return w;
2281}
2282#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
2283
2284void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end, const char* fmt, ...)
2285{
2286 va_list args;
2287 va_start(args, fmt);
2288 ImFormatStringToTempBufferV(out_buf, out_buf_end, fmt, args);
2289 va_end(args);
2290}
2291
2292// FIXME: Should rework API toward allowing multiple in-flight temp buffers (easier and safer for caller)
2293// by making the caller acquire a temp buffer token, with either explicit or destructor release, e.g.
2294// ImGuiTempBufferToken token;
2295// ImFormatStringToTempBuffer(token, ...);
2296void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args)
2297{
2298 ImGuiContext& g = *GImGui;
2299 if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
2300 {
2301 const char* buf = va_arg(args, const char*); // Skip formatting when using "%s"
2302 if (buf == NULL)
2303 buf = "(null)";
2304 *out_buf = buf;
2305 if (out_buf_end) { *out_buf_end = buf + ImStrlen(buf); }
2306 }
2307 else if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*' && fmt[3] == 's' && fmt[4] == 0)
2308 {
2309 int buf_len = va_arg(args, int); // Skip formatting when using "%.*s"
2310 const char* buf = va_arg(args, const char*);
2311 if (buf == NULL)
2312 {
2313 buf = "(null)";
2314 buf_len = ImMin(buf_len, 6);
2315 }
2316 *out_buf = buf;
2317 *out_buf_end = buf + buf_len; // Disallow not passing 'out_buf_end' here. User is expected to use it.
2318 }
2319 else
2320 {
2321 int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
2322 *out_buf = g.TempBuffer.Data;
2323 if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
2324 }
2325}
2326
2327#ifndef IMGUI_ENABLE_SSE4_2_CRC
2328// CRC32 needs a 1KB lookup table (not cache friendly)
2329// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
2330// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe.
2331static const ImU32 GCrc32LookupTable[256] =
2332{
2333#ifdef IMGUI_USE_LEGACY_CRC32_ADLER
2334 // Legacy CRC32-adler table used pre 1.91.6 (before 2024/11/27). Only use if you cannot afford invalidating old .ini data.
2335 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
2336 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
2337 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
2338 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
2339 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
2340 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
2341 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
2342 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
2343 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
2344 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
2345 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
2346 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
2347 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
2348 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
2349 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
2350 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
2351#else
2352 // CRC32c table compatible with SSE 4.2 instructions
2353 0x00000000,0xF26B8303,0xE13B70F7,0x1350F3F4,0xC79A971F,0x35F1141C,0x26A1E7E8,0xD4CA64EB,0x8AD958CF,0x78B2DBCC,0x6BE22838,0x9989AB3B,0x4D43CFD0,0xBF284CD3,0xAC78BF27,0x5E133C24,
2354 0x105EC76F,0xE235446C,0xF165B798,0x030E349B,0xD7C45070,0x25AFD373,0x36FF2087,0xC494A384,0x9A879FA0,0x68EC1CA3,0x7BBCEF57,0x89D76C54,0x5D1D08BF,0xAF768BBC,0xBC267848,0x4E4DFB4B,
2355 0x20BD8EDE,0xD2D60DDD,0xC186FE29,0x33ED7D2A,0xE72719C1,0x154C9AC2,0x061C6936,0xF477EA35,0xAA64D611,0x580F5512,0x4B5FA6E6,0xB93425E5,0x6DFE410E,0x9F95C20D,0x8CC531F9,0x7EAEB2FA,
2356 0x30E349B1,0xC288CAB2,0xD1D83946,0x23B3BA45,0xF779DEAE,0x05125DAD,0x1642AE59,0xE4292D5A,0xBA3A117E,0x4851927D,0x5B016189,0xA96AE28A,0x7DA08661,0x8FCB0562,0x9C9BF696,0x6EF07595,
2357 0x417B1DBC,0xB3109EBF,0xA0406D4B,0x522BEE48,0x86E18AA3,0x748A09A0,0x67DAFA54,0x95B17957,0xCBA24573,0x39C9C670,0x2A993584,0xD8F2B687,0x0C38D26C,0xFE53516F,0xED03A29B,0x1F682198,
2358 0x5125DAD3,0xA34E59D0,0xB01EAA24,0x42752927,0x96BF4DCC,0x64D4CECF,0x77843D3B,0x85EFBE38,0xDBFC821C,0x2997011F,0x3AC7F2EB,0xC8AC71E8,0x1C661503,0xEE0D9600,0xFD5D65F4,0x0F36E6F7,
2359 0x61C69362,0x93AD1061,0x80FDE395,0x72966096,0xA65C047D,0x5437877E,0x4767748A,0xB50CF789,0xEB1FCBAD,0x197448AE,0x0A24BB5A,0xF84F3859,0x2C855CB2,0xDEEEDFB1,0xCDBE2C45,0x3FD5AF46,
2360 0x7198540D,0x83F3D70E,0x90A324FA,0x62C8A7F9,0xB602C312,0x44694011,0x5739B3E5,0xA55230E6,0xFB410CC2,0x092A8FC1,0x1A7A7C35,0xE811FF36,0x3CDB9BDD,0xCEB018DE,0xDDE0EB2A,0x2F8B6829,
2361 0x82F63B78,0x709DB87B,0x63CD4B8F,0x91A6C88C,0x456CAC67,0xB7072F64,0xA457DC90,0x563C5F93,0x082F63B7,0xFA44E0B4,0xE9141340,0x1B7F9043,0xCFB5F4A8,0x3DDE77AB,0x2E8E845F,0xDCE5075C,
2362 0x92A8FC17,0x60C37F14,0x73938CE0,0x81F80FE3,0x55326B08,0xA759E80B,0xB4091BFF,0x466298FC,0x1871A4D8,0xEA1A27DB,0xF94AD42F,0x0B21572C,0xDFEB33C7,0x2D80B0C4,0x3ED04330,0xCCBBC033,
2363 0xA24BB5A6,0x502036A5,0x4370C551,0xB11B4652,0x65D122B9,0x97BAA1BA,0x84EA524E,0x7681D14D,0x2892ED69,0xDAF96E6A,0xC9A99D9E,0x3BC21E9D,0xEF087A76,0x1D63F975,0x0E330A81,0xFC588982,
2364 0xB21572C9,0x407EF1CA,0x532E023E,0xA145813D,0x758FE5D6,0x87E466D5,0x94B49521,0x66DF1622,0x38CC2A06,0xCAA7A905,0xD9F75AF1,0x2B9CD9F2,0xFF56BD19,0x0D3D3E1A,0x1E6DCDEE,0xEC064EED,
2365 0xC38D26C4,0x31E6A5C7,0x22B65633,0xD0DDD530,0x0417B1DB,0xF67C32D8,0xE52CC12C,0x1747422F,0x49547E0B,0xBB3FFD08,0xA86F0EFC,0x5A048DFF,0x8ECEE914,0x7CA56A17,0x6FF599E3,0x9D9E1AE0,
2366 0xD3D3E1AB,0x21B862A8,0x32E8915C,0xC083125F,0x144976B4,0xE622F5B7,0xF5720643,0x07198540,0x590AB964,0xAB613A67,0xB831C993,0x4A5A4A90,0x9E902E7B,0x6CFBAD78,0x7FAB5E8C,0x8DC0DD8F,
2367 0xE330A81A,0x115B2B19,0x020BD8ED,0xF0605BEE,0x24AA3F05,0xD6C1BC06,0xC5914FF2,0x37FACCF1,0x69E9F0D5,0x9B8273D6,0x88D28022,0x7AB90321,0xAE7367CA,0x5C18E4C9,0x4F48173D,0xBD23943E,
2368 0xF36E6F75,0x0105EC76,0x12551F82,0xE03E9C81,0x34F4F86A,0xC69F7B69,0xD5CF889D,0x27A40B9E,0x79B737BA,0x8BDCB4B9,0x988C474D,0x6AE7C44E,0xBE2DA0A5,0x4C4623A6,0x5F16D052,0xAD7D5351
2369#endif
2370};
2371#endif
2372
2373// Known size hash
2374// It is ok to call ImHashData on a string with known length but the ### operator won't be supported.
2375// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
2376ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed)
2377{
2378 ImU32 crc = ~seed;
2379 const unsigned char* data = (const unsigned char*)data_p;
2380 const unsigned char *data_end = (const unsigned char*)data_p + data_size;
2381#ifndef IMGUI_ENABLE_SSE4_2_CRC
2382 const ImU32* crc32_lut = GCrc32LookupTable;
2383 while (data < data_end)
2384 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
2385 return ~crc;
2386#else
2387 while (data + 4 <= data_end)
2388 {
2389 crc = _mm_crc32_u32(crc, *(ImU32*)data);
2390 data += 4;
2391 }
2392 while (data < data_end)
2393 crc = _mm_crc32_u8(crc, *data++);
2394 return ~crc;
2395#endif
2396}
2397
2398// Zero-terminated string hash, with support for ### to reset back to seed value
2399// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
2400// Because this syntax is rarely used we are optimizing for the common case.
2401// - If we reach ### in the string we discard the hash so far and reset to the seed.
2402// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)
2403// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
2404ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed)
2405{
2406 seed = ~seed;
2407 ImU32 crc = seed;
2408 const unsigned char* data = (const unsigned char*)data_p;
2409#ifndef IMGUI_ENABLE_SSE4_2_CRC
2410 const ImU32* crc32_lut = GCrc32LookupTable;
2411#endif
2412 if (data_size != 0)
2413 {
2414 while (data_size-- != 0)
2415 {
2416 unsigned char c = *data++;
2417 if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#')
2418 crc = seed;
2419#ifndef IMGUI_ENABLE_SSE4_2_CRC
2420 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
2421#else
2422 crc = _mm_crc32_u8(crc, c);
2423#endif
2424 }
2425 }
2426 else
2427 {
2428 while (unsigned char c = *data++)
2429 {
2430 if (c == '#' && data[0] == '#' && data[1] == '#')
2431 crc = seed;
2432#ifndef IMGUI_ENABLE_SSE4_2_CRC
2433 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
2434#else
2435 crc = _mm_crc32_u8(crc, c);
2436#endif
2437 }
2438 }
2439 return ~crc;
2440}
2441
2442//-----------------------------------------------------------------------------
2443// [SECTION] MISC HELPERS/UTILITIES (File functions)
2444//-----------------------------------------------------------------------------
2445
2446// Default file functions
2447#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
2448
2449ImFileHandle ImFileOpen(const char* filename, const char* mode)
2450{
2451#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && (defined(__MINGW32__) || (!defined(__CYGWIN__) && !defined(__GNUC__)))
2452 // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames.
2453 // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32!
2454 const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
2455 const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
2456
2457 // Use stack buffer if possible, otherwise heap buffer. Sizes include zero terminator.
2458 // We don't rely on current ImGuiContext as this is implied to be a helper function which doesn't depend on it (see #7314).
2459 wchar_t local_temp_stack[FILENAME_MAX];
2460 ImVector<wchar_t> local_temp_heap;
2461 if (filename_wsize + mode_wsize > IM_ARRAYSIZE(local_temp_stack))
2462 local_temp_heap.resize(filename_wsize + mode_wsize);
2463 wchar_t* filename_wbuf = local_temp_heap.Data ? local_temp_heap.Data : local_temp_stack;
2464 wchar_t* mode_wbuf = filename_wbuf + filename_wsize;
2465 ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, filename_wbuf, filename_wsize);
2466 ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, mode_wbuf, mode_wsize);
2467 return ::_wfopen(filename_wbuf, mode_wbuf);
2468#else
2469 return fopen(filename, mode);
2470#endif
2471}
2472
2473// We should in theory be using fseeko()/ftello() with off_t and _fseeki64()/_ftelli64() with __int64, waiting for the PR that does that in a very portable pre-C++11 zero-warnings way.
2474bool ImFileClose(ImFileHandle f) { return fclose(f) == 0; }
2475ImU64 ImFileGetSize(ImFileHandle f) { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; }
2476ImU64 ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fread(data, (size_t)sz, (size_t)count, f); }
2477ImU64 ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fwrite(data, (size_t)sz, (size_t)count, f); }
2478#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
2479
2480// Helper: Load file content into memory
2481// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
2482// This can't really be used with "rt" because fseek size won't match read size.
2483void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes)
2484{
2485 IM_ASSERT(filename && mode);
2486 if (out_file_size)
2487 *out_file_size = 0;
2488
2489 ImFileHandle f;
2490 if ((f = ImFileOpen(filename, mode)) == NULL)
2491 return NULL;
2492
2493 size_t file_size = (size_t)ImFileGetSize(f);
2494 if (file_size == (size_t)-1)
2495 {
2496 ImFileClose(f);
2497 return NULL;
2498 }
2499
2500 void* file_data = IM_ALLOC(file_size + padding_bytes);
2501 if (file_data == NULL)
2502 {
2503 ImFileClose(f);
2504 return NULL;
2505 }
2506 if (ImFileRead(file_data, 1, file_size, f) != file_size)
2507 {
2508 ImFileClose(f);
2509 IM_FREE(file_data);
2510 return NULL;
2511 }
2512 if (padding_bytes > 0)
2513 memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
2514
2515 ImFileClose(f);
2516 if (out_file_size)
2517 *out_file_size = file_size;
2518
2519 return file_data;
2520}
2521
2522//-----------------------------------------------------------------------------
2523// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
2524//-----------------------------------------------------------------------------
2525
2527
2528// Convert UTF-8 to 32-bit character, process single character input.
2529// A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8).
2530// We handle UTF-8 decoding error by skipping forward.
2531int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
2532{
2533 static const char lengths[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0 };
2534 static const int masks[] = { 0x00, 0x7f, 0x1f, 0x0f, 0x07 };
2535 static const uint32_t mins[] = { 0x400000, 0, 0x80, 0x800, 0x10000 };
2536 static const int shiftc[] = { 0, 18, 12, 6, 0 };
2537 static const int shifte[] = { 0, 6, 4, 2, 0 };
2538 int len = lengths[*(const unsigned char*)in_text >> 3];
2539 int wanted = len + (len ? 0 : 1);
2540
2541 if (in_text_end == NULL)
2542 in_text_end = in_text + wanted; // Max length, nulls will be taken into account.
2543
2544 // Copy at most 'len' bytes, stop copying at 0 or past in_text_end. Branch predictor does a good job here,
2545 // so it is fast even with excessive branching.
2546 unsigned char s[4];
2547 s[0] = in_text + 0 < in_text_end ? in_text[0] : 0;
2548 s[1] = in_text + 1 < in_text_end ? in_text[1] : 0;
2549 s[2] = in_text + 2 < in_text_end ? in_text[2] : 0;
2550 s[3] = in_text + 3 < in_text_end ? in_text[3] : 0;
2551
2552 // Assume a four-byte character and load four bytes. Unused bits are shifted out.
2553 *out_char = (uint32_t)(s[0] & masks[len]) << 18;
2554 *out_char |= (uint32_t)(s[1] & 0x3f) << 12;
2555 *out_char |= (uint32_t)(s[2] & 0x3f) << 6;
2556 *out_char |= (uint32_t)(s[3] & 0x3f) << 0;
2557 *out_char >>= shiftc[len];
2558
2559 // Accumulate the various error conditions.
2560 int e = 0;
2561 e = (*out_char < mins[len]) << 6; // non-canonical encoding
2562 e |= ((*out_char >> 11) == 0x1b) << 7; // surrogate half?
2563 e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8; // out of range we can store in ImWchar (FIXME: May evolve)
2564 e |= (s[1] & 0xc0) >> 2;
2565 e |= (s[2] & 0xc0) >> 4;
2566 e |= (s[3] ) >> 6;
2567 e ^= 0x2a; // top two bits of each tail byte correct?
2568 e >>= shifte[len];
2569
2570 if (e)
2571 {
2572 // No bytes are consumed when *in_text == 0 || in_text == in_text_end.
2573 // One byte is consumed in case of invalid first byte of in_text.
2574 // All available bytes (at most `len` bytes) are consumed on incomplete/invalid second to last bytes.
2575 // Invalid or incomplete input may consume less bytes than wanted, therefore every byte has to be inspected in s.
2576 wanted = ImMin(wanted, !!s[0] + !!s[1] + !!s[2] + !!s[3]);
2577 *out_char = IM_UNICODE_CODEPOINT_INVALID;
2578 }
2579
2580 return wanted;
2581}
2582
2583int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
2584{
2585 ImWchar* buf_out = buf;
2586 ImWchar* buf_end = buf + buf_size;
2587 while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
2588 {
2589 unsigned int c;
2590 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
2591 *buf_out++ = (ImWchar)c;
2592 }
2593 *buf_out = 0;
2594 if (in_text_remaining)
2595 *in_text_remaining = in_text;
2596 return (int)(buf_out - buf);
2597}
2598
2599int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
2600{
2601 int char_count = 0;
2602 while ((!in_text_end || in_text < in_text_end) && *in_text)
2603 {
2604 unsigned int c;
2605 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
2606 char_count++;
2607 }
2608 return char_count;
2609}
2610
2611// Based on stb_to_utf8() from github.com/nothings/stb/
2612static inline int ImTextCharToUtf8_inline(char* buf, int buf_size, unsigned int c)
2613{
2614 if (c < 0x80)
2615 {
2616 buf[0] = (char)c;
2617 return 1;
2618 }
2619 if (c < 0x800)
2620 {
2621 if (buf_size < 2) return 0;
2622 buf[0] = (char)(0xc0 + (c >> 6));
2623 buf[1] = (char)(0x80 + (c & 0x3f));
2624 return 2;
2625 }
2626 if (c < 0x10000)
2627 {
2628 if (buf_size < 3) return 0;
2629 buf[0] = (char)(0xe0 + (c >> 12));
2630 buf[1] = (char)(0x80 + ((c >> 6) & 0x3f));
2631 buf[2] = (char)(0x80 + ((c ) & 0x3f));
2632 return 3;
2633 }
2634 if (c <= 0x10FFFF)
2635 {
2636 if (buf_size < 4) return 0;
2637 buf[0] = (char)(0xf0 + (c >> 18));
2638 buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
2639 buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
2640 buf[3] = (char)(0x80 + ((c ) & 0x3f));
2641 return 4;
2642 }
2643 // Invalid code point, the max unicode is 0x10FFFF
2644 return 0;
2645}
2646
2647const char* ImTextCharToUtf8(char out_buf[5], unsigned int c)
2648{
2649 int count = ImTextCharToUtf8_inline(out_buf, 5, c);
2650 out_buf[count] = 0;
2651 return out_buf;
2652}
2653
2654// Not optimal but we very rarely use this function.
2655int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)
2656{
2657 unsigned int unused = 0;
2658 return ImTextCharFromUtf8(&unused, in_text, in_text_end);
2659}
2660
2661static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
2662{
2663 if (c < 0x80) return 1;
2664 if (c < 0x800) return 2;
2665 if (c < 0x10000) return 3;
2666 if (c <= 0x10FFFF) return 4;
2667 return 3;
2668}
2669
2670int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
2671{
2672 char* buf_p = out_buf;
2673 const char* buf_end = out_buf + out_buf_size;
2674 while (buf_p < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
2675 {
2676 unsigned int c = (unsigned int)(*in_text++);
2677 if (c < 0x80)
2678 *buf_p++ = (char)c;
2679 else
2680 buf_p += ImTextCharToUtf8_inline(buf_p, (int)(buf_end - buf_p - 1), c);
2681 }
2682 *buf_p = 0;
2683 return (int)(buf_p - out_buf);
2684}
2685
2686int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
2687{
2688 int bytes_count = 0;
2689 while ((!in_text_end || in_text < in_text_end) && *in_text)
2690 {
2691 unsigned int c = (unsigned int)(*in_text++);
2692 if (c < 0x80)
2693 bytes_count++;
2694 else
2695 bytes_count += ImTextCountUtf8BytesFromChar(c);
2696 }
2697 return bytes_count;
2698}
2699
2700const char* ImTextFindPreviousUtf8Codepoint(const char* in_text_start, const char* in_text_curr)
2701{
2702 while (in_text_curr > in_text_start)
2703 {
2704 in_text_curr--;
2705 if ((*in_text_curr & 0xC0) != 0x80)
2706 return in_text_curr;
2707 }
2708 return in_text_start;
2709}
2710
2711int ImTextCountLines(const char* in_text, const char* in_text_end)
2712{
2713 if (in_text_end == NULL)
2714 in_text_end = in_text + ImStrlen(in_text); // FIXME-OPT: Not optimal approach, discourage use for now.
2715 int count = 0;
2716 while (in_text < in_text_end)
2717 {
2718 const char* line_end = (const char*)ImMemchr(in_text, '\n', in_text_end - in_text);
2719 in_text = line_end ? line_end + 1 : in_text_end;
2720 count++;
2721 }
2722 return count;
2723}
2724
2726
2727//-----------------------------------------------------------------------------
2728// [SECTION] MISC HELPERS/UTILITIES (Color functions)
2729// Note: The Convert functions are early design which are not consistent with other API.
2730//-----------------------------------------------------------------------------
2731
2733{
2734 float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
2735 int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
2736 int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
2737 int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
2738 return IM_COL32(r, g, b, 0xFF);
2739}
2740
2742{
2743 float s = 1.0f / 255.0f;
2744 return ImVec4(
2745 ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
2746 ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
2747 ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
2748 ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
2749}
2750
2752{
2753 ImU32 out;
2755 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
2756 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
2757 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
2758 return out;
2759}
2760
2761// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
2762// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
2763void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
2764{
2765 float K = 0.f;
2766 if (g < b)
2767 {
2768 ImSwap(g, b);
2769 K = -1.f;
2770 }
2771 if (r < g)
2772 {
2773 ImSwap(r, g);
2774 K = -2.f / 6.f - K;
2775 }
2776
2777 const float chroma = r - (g < b ? g : b);
2778 out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));
2779 out_s = chroma / (r + 1e-20f);
2780 out_v = r;
2781}
2782
2783// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
2784// also http://en.wikipedia.org/wiki/HSL_and_HSV
2785void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
2786{
2787 if (s == 0.0f)
2788 {
2789 // gray
2790 out_r = out_g = out_b = v;
2791 return;
2792 }
2793
2794 h = ImFmod(h, 1.0f) / (60.0f / 360.0f);
2795 int i = (int)h;
2796 float f = h - (float)i;
2797 float p = v * (1.0f - s);
2798 float q = v * (1.0f - s * f);
2799 float t = v * (1.0f - s * (1.0f - f));
2800
2801 switch (i)
2802 {
2803 case 0: out_r = v; out_g = t; out_b = p; break;
2804 case 1: out_r = q; out_g = v; out_b = p; break;
2805 case 2: out_r = p; out_g = v; out_b = t; break;
2806 case 3: out_r = p; out_g = q; out_b = v; break;
2807 case 4: out_r = t; out_g = p; out_b = v; break;
2808 case 5: default: out_r = v; out_g = p; out_b = q; break;
2809 }
2810}
2811
2812//-----------------------------------------------------------------------------
2813// [SECTION] ImGuiStorage
2814// Helper: Key->value storage
2815//-----------------------------------------------------------------------------
2816
2817// std::lower_bound but without the bullshit
2819{
2820 ImGuiStoragePair* in_p = in_begin;
2821 for (size_t count = (size_t)(in_end - in_p); count > 0; )
2822 {
2823 size_t count2 = count >> 1;
2824 ImGuiStoragePair* mid = in_p + count2;
2825 if (mid->key < key)
2826 {
2827 in_p = ++mid;
2828 count -= count2 + 1;
2829 }
2830 else
2831 {
2832 count = count2;
2833 }
2834 }
2835 return in_p;
2836}
2837
2839static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs)
2840{
2841 // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
2842 ImGuiID lhs_v = ((const ImGuiStoragePair*)lhs)->key;
2843 ImGuiID rhs_v = ((const ImGuiStoragePair*)rhs)->key;
2844 return (lhs_v > rhs_v ? +1 : lhs_v < rhs_v ? -1 : 0);
2845}
2846
2847// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
2849{
2851}
2852
2853int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
2854{
2855 ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
2856 if (it == Data.Data + Data.Size || it->key != key)
2857 return default_val;
2858 return it->val_i;
2859}
2860
2861bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
2862{
2863 return GetInt(key, default_val ? 1 : 0) != 0;
2864}
2865
2866float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
2867{
2868 ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
2869 if (it == Data.Data + Data.Size || it->key != key)
2870 return default_val;
2871 return it->val_f;
2872}
2873
2875{
2876 ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
2877 if (it == Data.Data + Data.Size || it->key != key)
2878 return NULL;
2879 return it->val_p;
2880}
2881
2882// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
2883int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
2884{
2886 if (it == Data.Data + Data.Size || it->key != key)
2887 it = Data.insert(it, ImGuiStoragePair(key, default_val));
2888 return &it->val_i;
2889}
2890
2891bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
2892{
2893 return (bool*)GetIntRef(key, default_val ? 1 : 0);
2894}
2895
2896float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
2897{
2899 if (it == Data.Data + Data.Size || it->key != key)
2900 it = Data.insert(it, ImGuiStoragePair(key, default_val));
2901 return &it->val_f;
2902}
2903
2904void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
2905{
2907 if (it == Data.Data + Data.Size || it->key != key)
2908 it = Data.insert(it, ImGuiStoragePair(key, default_val));
2909 return &it->val_p;
2910}
2911
2912// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
2914{
2916 if (it == Data.Data + Data.Size || it->key != key)
2917 Data.insert(it, ImGuiStoragePair(key, val));
2918 else
2919 it->val_i = val;
2920}
2921
2923{
2924 SetInt(key, val ? 1 : 0);
2925}
2926
2928{
2930 if (it == Data.Data + Data.Size || it->key != key)
2931 Data.insert(it, ImGuiStoragePair(key, val));
2932 else
2933 it->val_f = val;
2934}
2935
2937{
2939 if (it == Data.Data + Data.Size || it->key != key)
2940 Data.insert(it, ImGuiStoragePair(key, val));
2941 else
2942 it->val_p = val;
2943}
2944
2946{
2947 for (int i = 0; i < Data.Size; i++)
2948 Data[i].val_i = v;
2949}
2951
2952//-----------------------------------------------------------------------------
2953// [SECTION] ImGuiTextFilter
2954//-----------------------------------------------------------------------------
2955
2956// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
2957ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077
2958{
2959 InputBuf[0] = 0;
2960 CountGrep = 0;
2961 if (default_filter)
2962 {
2963 ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
2964 Build();
2965 }
2966}
2967
2968bool ImGuiTextFilter::Draw(const char* label, float width)
2969{
2970 if (width != 0.0f)
2972 bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
2973 if (value_changed)
2974 Build();
2975 return value_changed;
2976}
2977
2979{
2980 out->resize(0);
2981 const char* wb = b;
2982 const char* we = wb;
2983 while (we < e)
2984 {
2985 if (*we == separator)
2986 {
2987 out->push_back(ImGuiTextRange(wb, we));
2988 wb = we + 1;
2989 }
2990 we++;
2991 }
2992 if (wb != we)
2993 out->push_back(ImGuiTextRange(wb, we));
2994}
2995
2997{
2998 Filters.resize(0);
3000 input_range.split(',', &Filters);
3001
3002 CountGrep = 0;
3003 for (ImGuiTextRange& f : Filters)
3004 {
3005 while (f.b < f.e && ImCharIsBlankA(f.b[0]))
3006 f.b++;
3007 while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
3008 f.e--;
3009 if (f.empty())
3010 continue;
3011 if (f.b[0] != '-')
3012 CountGrep += 1;
3013 }
3014}
3015
3016bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
3017{
3018 if (Filters.Size == 0)
3019 return true;
3020
3021 if (text == NULL)
3022 text = text_end = "";
3023
3024 for (const ImGuiTextRange& f : Filters)
3025 {
3026 if (f.b == f.e)
3027 continue;
3028 if (f.b[0] == '-')
3029 {
3030 // Subtract
3031 if (ImStristr(text, text_end, f.b + 1, f.e) != NULL)
3032 return false;
3033 }
3034 else
3035 {
3036 // Grep
3037 if (ImStristr(text, text_end, f.b, f.e) != NULL)
3038 return true;
3039 }
3040 }
3041
3042 // Implicit * grep
3043 if (CountGrep == 0)
3044 return true;
3045
3046 return false;
3047}
3048
3049//-----------------------------------------------------------------------------
3050// [SECTION] ImGuiTextBuffer, ImGuiTextIndex
3051//-----------------------------------------------------------------------------
3052
3053// On some platform vsnprintf() takes va_list by reference and modifies it.
3054// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
3055#ifndef va_copy
3056#if defined(__GNUC__) || defined(__clang__)
3057#define va_copy(dest, src) __builtin_va_copy(dest, src)
3058#else
3059#define va_copy(dest, src) (dest = src)
3060#endif
3061#endif
3062
3063char ImGuiTextBuffer::EmptyString[1] = { 0 };
3064
3065void ImGuiTextBuffer::append(const char* str, const char* str_end)
3066{
3067 int len = str_end ? (int)(str_end - str) : (int)ImStrlen(str);
3068
3069 // Add zero-terminator the first time
3070 const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
3071 const int needed_sz = write_off + len;
3072 if (write_off + len >= Buf.Capacity)
3073 {
3074 int new_capacity = Buf.Capacity * 2;
3075 Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
3076 }
3077
3078 Buf.resize(needed_sz);
3079 memcpy(&Buf[write_off - 1], str, (size_t)len);
3080 Buf[write_off - 1 + len] = 0;
3081}
3082
3083void ImGuiTextBuffer::appendf(const char* fmt, ...)
3084{
3085 va_list args;
3086 va_start(args, fmt);
3087 appendfv(fmt, args);
3088 va_end(args);
3089}
3090
3091// Helper: Text buffer for logging/accumulating text
3092void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
3093{
3094 va_list args_copy;
3095 va_copy(args_copy, args);
3096
3097 int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
3098 if (len <= 0)
3099 {
3100 va_end(args_copy);
3101 return;
3102 }
3103
3104 // Add zero-terminator the first time
3105 const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
3106 const int needed_sz = write_off + len;
3107 if (write_off + len >= Buf.Capacity)
3108 {
3109 int new_capacity = Buf.Capacity * 2;
3110 Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
3111 }
3112
3113 Buf.resize(needed_sz);
3114 ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
3115 va_end(args_copy);
3116}
3117
3118void ImGuiTextIndex::append(const char* base, int old_size, int new_size)
3119{
3120 IM_ASSERT(old_size >= 0 && new_size >= old_size && new_size >= EndOffset);
3121 if (old_size == new_size)
3122 return;
3123 if (EndOffset == 0 || base[EndOffset - 1] == '\n')
3124 LineOffsets.push_back(EndOffset);
3125 const char* base_end = base + new_size;
3126 for (const char* p = base + old_size; (p = (const char*)ImMemchr(p, '\n', base_end - p)) != 0; )
3127 if (++p < base_end) // Don't push a trailing offset on last \n
3128 LineOffsets.push_back((int)(intptr_t)(p - base));
3129 EndOffset = ImMax(EndOffset, new_size);
3130}
3131
3132//-----------------------------------------------------------------------------
3133// [SECTION] ImGuiListClipper
3134//-----------------------------------------------------------------------------
3135
3136// FIXME-TABLE: This prevents us from using ImGuiListClipper _inside_ a table cell.
3137// The problem we have is that without a Begin/End scheme for rows using the clipper is ambiguous.
3139{
3140 ImGuiContext& g = *GImGui;
3142}
3143
3145{
3146 if (ranges.Size - offset <= 1)
3147 return;
3148
3149 // Helper to order ranges and fuse them together if possible (bubble sort is fine as we are only sorting 2-3 entries)
3150 for (int sort_end = ranges.Size - offset - 1; sort_end > 0; --sort_end)
3151 for (int i = offset; i < sort_end + offset; ++i)
3152 if (ranges[i].Min > ranges[i + 1].Min)
3153 ImSwap(ranges[i], ranges[i + 1]);
3154
3155 // Now fuse ranges together as much as possible.
3156 for (int i = 1 + offset; i < ranges.Size; i++)
3157 {
3158 IM_ASSERT(!ranges[i].PosToIndexConvert && !ranges[i - 1].PosToIndexConvert);
3159 if (ranges[i - 1].Max < ranges[i].Min)
3160 continue;
3161 ranges[i - 1].Min = ImMin(ranges[i - 1].Min, ranges[i].Min);
3162 ranges[i - 1].Max = ImMax(ranges[i - 1].Max, ranges[i].Max);
3163 ranges.erase(ranges.Data + i);
3164 i--;
3165 }
3166}
3167
3168static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_height)
3169{
3170 // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
3171 // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
3172 // The clipper should probably have a final step to display the last item in a regular manner, maybe with an opt-out flag for data sets which may have costly seek?
3173 ImGuiContext& g = *GImGui;
3174 ImGuiWindow* window = g.CurrentWindow;
3175 float off_y = pos_y - window->DC.CursorPos.y;
3176 window->DC.CursorPos.y = pos_y;
3177 window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y - g.Style.ItemSpacing.y);
3178 window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage.
3179 window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
3180 if (ImGuiOldColumns* columns = window->DC.CurrentColumns)
3181 columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
3182 if (ImGuiTable* table = g.CurrentTable)
3183 {
3184 if (table->IsInsideRow)
3185 ImGui::TableEndRow(table);
3186 table->RowPosY2 = window->DC.CursorPos.y;
3187 const int row_increase = (int)((off_y / line_height) + 0.5f);
3188 //table->CurrentRow += row_increase; // Can't do without fixing TableEndRow()
3189 table->RowBgColorCounter += row_increase;
3190 }
3191}
3192
3194{
3195 memset(this, 0, sizeof(*this));
3196}
3197
3199{
3200 End();
3201}
3202
3203void ImGuiListClipper::Begin(int items_count, float items_height)
3204{
3205 if (Ctx == NULL)
3207
3208 ImGuiContext& g = *Ctx;
3209 ImGuiWindow* window = g.CurrentWindow;
3210 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Begin(%d,%.2f) in '%s'\n", items_count, items_height, window->Name);
3211
3212 if (ImGuiTable* table = g.CurrentTable)
3213 if (table->IsInsideRow)
3214 ImGui::TableEndRow(table);
3215
3216 StartPosY = window->DC.CursorPos.y;
3217 ItemsHeight = items_height;
3218 ItemsCount = items_count;
3219 DisplayStart = -1;
3220 DisplayEnd = 0;
3221
3222 // Acquire temporary buffer
3226 data->Reset(this);
3228 TempData = data;
3229 StartSeekOffsetY = data->LossynessOffset;
3230}
3231
3233{
3234 if (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData)
3235 {
3236 // In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user.
3237 ImGuiContext& g = *Ctx;
3238 IMGUI_DEBUG_LOG_CLIPPER("Clipper: End() in '%s'\n", g.CurrentWindow->Name);
3239 if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0)
3240 SeekCursorForItem(ItemsCount);
3241
3242 // Restore temporary buffer and fix back pointers which may be invalidated when nesting
3243 IM_ASSERT(data->ListClipper == this);
3244 data->StepNo = data->Ranges.Size;
3245 if (--g.ClipperTempDataStacked > 0)
3246 {
3247 data = &g.ClipperTempData[g.ClipperTempDataStacked - 1];
3248 data->ListClipper->TempData = data;
3249 }
3250 TempData = NULL;
3251 }
3252 ItemsCount = -1;
3253}
3254
3255void ImGuiListClipper::IncludeItemsByIndex(int item_begin, int item_end)
3256{
3257 ImGuiListClipperData* data = (ImGuiListClipperData*)TempData;
3258 IM_ASSERT(DisplayStart < 0); // Only allowed after Begin() and if there has not been a specified range yet.
3259 IM_ASSERT(item_begin <= item_end);
3260 if (item_begin < item_end)
3261 data->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_begin, item_end));
3262}
3263
3264// This is already called while stepping.
3265// The ONLY reason you may want to call this is if you passed INT_MAX to ImGuiListClipper::Begin() because you couldn't step item count beforehand.
3267{
3268 // - Perform the add and multiply with double to allow seeking through larger ranges.
3269 // - StartPosY starts from ItemsFrozen, by adding SeekOffsetY we generally cancel that out (SeekOffsetY == LossynessOffset - ItemsFrozen * ItemsHeight).
3270 // - The reason we store SeekOffsetY instead of inferring it, is because we want to allow user to perform Seek after the last step, where ImGuiListClipperData is already done.
3271 float pos_y = (float)((double)StartPosY + StartSeekOffsetY + (double)item_n * ItemsHeight);
3273}
3274
3276{
3277 ImGuiContext& g = *clipper->Ctx;
3278 ImGuiWindow* window = g.CurrentWindow;
3280 IM_ASSERT(data != NULL && "Called ImGuiListClipper::Step() too many times, or before ImGuiListClipper::Begin() ?");
3281
3282 ImGuiTable* table = g.CurrentTable;
3283 if (table && table->IsInsideRow)
3284 ImGui::TableEndRow(table);
3285
3286 // No items
3287 if (clipper->ItemsCount == 0 || GetSkipItemForListClipping())
3288 return false;
3289
3290 // While we are in frozen row state, keep displaying items one by one, unclipped
3291 // FIXME: Could be stored as a table-agnostic state.
3292 if (data->StepNo == 0 && table != NULL && !table->IsUnfrozenRows)
3293 {
3294 clipper->DisplayStart = data->ItemsFrozen;
3295 clipper->DisplayEnd = ImMin(data->ItemsFrozen + 1, clipper->ItemsCount);
3296 if (clipper->DisplayStart < clipper->DisplayEnd)
3297 data->ItemsFrozen++;
3298 return true;
3299 }
3300
3301 // Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height)
3302 bool calc_clipping = false;
3303 if (data->StepNo == 0)
3304 {
3305 clipper->StartPosY = window->DC.CursorPos.y;
3306 if (clipper->ItemsHeight <= 0.0f)
3307 {
3308 // Submit the first item (or range) so we can measure its height (generally the first range is 0..1)
3310 clipper->DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen);
3311 clipper->DisplayEnd = ImMin(data->Ranges[0].Max, clipper->ItemsCount);
3312 data->StepNo = 1;
3313 return true;
3314 }
3315 calc_clipping = true; // If on the first step with known item height, calculate clipping.
3316 }
3317
3318 // Step 1: Let the clipper infer height from first range
3319 if (clipper->ItemsHeight <= 0.0f)
3320 {
3321 IM_ASSERT(data->StepNo == 1);
3322 if (table)
3323 IM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y);
3324
3325 bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision((float)clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y);
3326 if (affected_by_floating_point_precision)
3327 {
3328 // Mitigation/hack for very large range: assume last time height constitute line height.
3329 clipper->ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries.
3330 window->DC.CursorPos.y = (float)(clipper->StartPosY + clipper->ItemsHeight);
3331 }
3332 else
3333 {
3334 clipper->ItemsHeight = (float)(window->DC.CursorPos.y - clipper->StartPosY) / (float)(clipper->DisplayEnd - clipper->DisplayStart);
3335 }
3336 if (clipper->ItemsHeight == 0.0f && clipper->ItemsCount == INT_MAX) // Accept that no item have been submitted if in indeterminate mode.
3337 return false;
3338 IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!");
3339 calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards.
3340 }
3341
3342 // Step 0 or 1: Calculate the actual ranges of visible elements.
3343 const int already_submitted = clipper->DisplayEnd;
3344 if (calc_clipping)
3345 {
3346 // Record seek offset, this is so ImGuiListClipper::Seek() can be called after ImGuiListClipperData is done
3347 clipper->StartSeekOffsetY = (double)data->LossynessOffset - data->ItemsFrozen * (double)clipper->ItemsHeight;
3348
3349 if (g.LogEnabled)
3350 {
3351 // If logging is active, do not perform any clipping
3353 }
3354 else
3355 {
3356 // Add range selected to be included for navigation
3357 const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
3358 if (is_nav_request)
3359 {
3362 }
3363 if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && g.NavTabbingDir == -1)
3365
3366 // Add focused/active item
3367 ImRect nav_rect_abs = ImGui::WindowRectRelToAbs(window, window->NavRectRel[0]);
3368 if (g.NavId != 0 && window->NavLastIds[0] == g.NavId)
3369 data->Ranges.push_back(ImGuiListClipperRange::FromPositions(nav_rect_abs.Min.y, nav_rect_abs.Max.y, 0, 0));
3370
3371 // Add visible range
3372 float min_y = window->ClipRect.Min.y;
3373 float max_y = window->ClipRect.Max.y;
3374
3375 // Add box selection range
3377 if (bs->IsActive && bs->Window == window)
3378 {
3379 // FIXME: Selectable() use of half-ItemSpacing isn't consistent in matter of layout, as ItemAdd(bb) stray above ItemSize()'s CursorPos.
3380 // RangeSelect's BoxSelect relies on comparing overlap of previous and current rectangle and is sensitive to that.
3381 // As a workaround we currently half ItemSpacing worth on each side.
3382 min_y -= g.Style.ItemSpacing.y;
3383 max_y += g.Style.ItemSpacing.y;
3384
3385 // Box-select on 2D area requires different clipping.
3386 if (bs->UnclipMode)
3388 }
3389
3390 const int off_min = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) ? -1 : 0;
3391 const int off_max = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) ? 1 : 0;
3392 data->Ranges.push_back(ImGuiListClipperRange::FromPositions(min_y, max_y, off_min, off_max));
3393 }
3394
3395 // Convert position ranges to item index ranges
3396 // - Very important: when a starting position is after our maximum item, we set Min to (ItemsCount - 1). This allows us to handle most forms of wrapping.
3397 // - Due to how Selectable extra padding they tend to be "unaligned" with exact unit in the item list,
3398 // which with the flooring/ceiling tend to lead to 2 items instead of one being submitted.
3399 for (ImGuiListClipperRange& range : data->Ranges)
3400 if (range.PosToIndexConvert)
3401 {
3402 int m1 = (int)(((double)range.Min - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight);
3403 int m2 = (int)((((double)range.Max - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight) + 0.999999f);
3404 range.Min = ImClamp(already_submitted + m1 + range.PosToIndexOffsetMin, already_submitted, clipper->ItemsCount - 1);
3405 range.Max = ImClamp(already_submitted + m2 + range.PosToIndexOffsetMax, range.Min + 1, clipper->ItemsCount);
3406 range.PosToIndexConvert = false;
3407 }
3409 }
3410
3411 // Step 0+ (if item height is given in advance) or 1+: Display the next range in line.
3412 while (data->StepNo < data->Ranges.Size)
3413 {
3414 clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted);
3415 clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount);
3416 data->StepNo++;
3417 if (clipper->DisplayStart >= clipper->DisplayEnd)
3418 continue;
3419 if (clipper->DisplayStart > already_submitted)
3420 clipper->SeekCursorForItem(clipper->DisplayStart);
3421 return true;
3422 }
3423
3424 // After the last step: Let the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd),
3425 // Advance the cursor to the end of the list and then returns 'false' to end the loop.
3426 if (clipper->ItemsCount < INT_MAX)
3427 clipper->SeekCursorForItem(clipper->ItemsCount);
3428
3429 return false;
3430}
3431
3433{
3434 ImGuiContext& g = *Ctx;
3435 bool need_items_height = (ItemsHeight <= 0.0f);
3436 bool ret = ImGuiListClipper_StepInternal(this);
3437 if (ret && (DisplayStart >= DisplayEnd))
3438 ret = false;
3439 if (g.CurrentTable && g.CurrentTable->IsUnfrozenRows == false)
3440 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): inside frozen table row.\n");
3441 if (need_items_height && ItemsHeight > 0.0f)
3442 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): computed ItemsHeight: %.2f.\n", ItemsHeight);
3443 if (ret)
3444 {
3445 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): display %d to %d.\n", DisplayStart, DisplayEnd);
3446 }
3447 else
3448 {
3449 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): End.\n");
3450 End();
3451 }
3452 return ret;
3453}
3454
3455//-----------------------------------------------------------------------------
3456// [SECTION] STYLING
3457//-----------------------------------------------------------------------------
3458
3460{
3461 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
3462 return GImGui->Style;
3463}
3464
3465ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
3466{
3467 ImGuiStyle& style = GImGui->Style;
3468 ImVec4 c = style.Colors[idx];
3469 c.w *= style.Alpha * alpha_mul;
3470 return ColorConvertFloat4ToU32(c);
3471}
3472
3474{
3475 ImGuiStyle& style = GImGui->Style;
3476 ImVec4 c = col;
3477 c.w *= style.Alpha;
3478 return ColorConvertFloat4ToU32(c);
3479}
3480
3482{
3483 ImGuiStyle& style = GImGui->Style;
3484 return style.Colors[idx];
3485}
3486
3487ImU32 ImGui::GetColorU32(ImU32 col, float alpha_mul)
3488{
3489 ImGuiStyle& style = GImGui->Style;
3490 alpha_mul *= style.Alpha;
3491 if (alpha_mul >= 1.0f)
3492 return col;
3493 ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
3494 a = (ImU32)(a * alpha_mul); // We don't need to clamp 0..255 because alpha is in 0..1 range.
3495 return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
3496}
3497
3498// FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32
3500{
3501 ImGuiContext& g = *GImGui;
3502 ImGuiColorMod backup;
3503 backup.Col = idx;
3504 backup.BackupValue = g.Style.Colors[idx];
3505 g.ColorStack.push_back(backup);
3506 if (g.DebugFlashStyleColorIdx != idx)
3507 g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
3508}
3509
3511{
3512 ImGuiContext& g = *GImGui;
3513 ImGuiColorMod backup;
3514 backup.Col = idx;
3515 backup.BackupValue = g.Style.Colors[idx];
3516 g.ColorStack.push_back(backup);
3517 if (g.DebugFlashStyleColorIdx != idx)
3518 g.Style.Colors[idx] = col;
3519}
3520
3522{
3523 ImGuiContext& g = *GImGui;
3524 if (g.ColorStack.Size < count)
3525 {
3526 IM_ASSERT_USER_ERROR(0, "Calling PopStyleColor() too many times!");
3527 count = g.ColorStack.Size;
3528 }
3529 while (count > 0)
3530 {
3531 ImGuiColorMod& backup = g.ColorStack.back();
3532 g.Style.Colors[backup.Col] = backup.BackupValue;
3533 g.ColorStack.pop_back();
3534 count--;
3535 }
3536}
3537
3539{
3541};
3542
3544{
3545 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha
3546 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha
3547 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding
3548 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding
3549 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize
3550 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize
3551 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign
3552 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding
3553 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize
3554 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding
3555 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize
3556 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding
3557 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding
3558 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize
3559 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing
3560 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing
3561 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing
3562 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, CellPadding) }, // ImGuiStyleVar_CellPadding
3563 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize
3564 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding
3565 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize
3566 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding
3567 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ImageBorderSize) }, // ImGuiStyleVar_ImageBorderSize
3568 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding
3569 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize
3570 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize
3571 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBarOverlineSize) }, // ImGuiStyleVar_TabBarOverlineSize
3572 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle
3573 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign
3574 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesSize)}, // ImGuiStyleVar_TreeLinesSize
3575 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesRounding)}, // ImGuiStyleVar_TreeLinesRounding
3576 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
3577 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
3578 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize
3579 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign
3580 { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding
3581 { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, DockingSeparatorSize) }, // ImGuiStyleVar_DockingSeparatorSize
3582};
3583
3585{
3586 IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);
3588 return &GStyleVarsInfo[idx];
3589}
3590
3592{
3593 ImGuiContext& g = *GImGui;
3594 const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
3595 if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 1)
3596 {
3597 IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
3598 return;
3599 }
3600 float* pvar = (float*)var_info->GetVarPtr(&g.Style);
3601 g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
3602 *pvar = val;
3603}
3604
3606{
3607 ImGuiContext& g = *GImGui;
3608 const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
3609 if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2)
3610 {
3611 IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
3612 return;
3613 }
3614 ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
3615 g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
3616 pvar->x = val_x;
3617}
3618
3620{
3621 ImGuiContext& g = *GImGui;
3622 const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
3623 if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2)
3624 {
3625 IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
3626 return;
3627 }
3628 ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
3629 g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
3630 pvar->y = val_y;
3631}
3632
3634{
3635 ImGuiContext& g = *GImGui;
3636 const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
3637 if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2)
3638 {
3639 IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
3640 return;
3641 }
3642 ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
3643 g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
3644 *pvar = val;
3645}
3646
3647void ImGui::PopStyleVar(int count)
3648{
3649 ImGuiContext& g = *GImGui;
3650 if (g.StyleVarStack.Size < count)
3651 {
3652 IM_ASSERT_USER_ERROR(0, "Calling PopStyleVar() too many times!");
3653 count = g.StyleVarStack.Size;
3654 }
3655 while (count > 0)
3656 {
3657 // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.
3658 ImGuiStyleMod& backup = g.StyleVarStack.back();
3659 const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(backup.VarIdx);
3660 void* data = var_info->GetVarPtr(&g.Style);
3661 if (var_info->DataType == ImGuiDataType_Float && var_info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; }
3662 else if (var_info->DataType == ImGuiDataType_Float && var_info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }
3664 count--;
3665 }
3666}
3667
3669{
3670 // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
3671 switch (idx)
3672 {
3673 case ImGuiCol_Text: return "Text";
3674 case ImGuiCol_TextDisabled: return "TextDisabled";
3675 case ImGuiCol_WindowBg: return "WindowBg";
3676 case ImGuiCol_ChildBg: return "ChildBg";
3677 case ImGuiCol_PopupBg: return "PopupBg";
3678 case ImGuiCol_Border: return "Border";
3679 case ImGuiCol_BorderShadow: return "BorderShadow";
3680 case ImGuiCol_FrameBg: return "FrameBg";
3681 case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
3682 case ImGuiCol_FrameBgActive: return "FrameBgActive";
3683 case ImGuiCol_TitleBg: return "TitleBg";
3684 case ImGuiCol_TitleBgActive: return "TitleBgActive";
3685 case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
3686 case ImGuiCol_MenuBarBg: return "MenuBarBg";
3687 case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
3688 case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
3689 case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
3690 case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
3691 case ImGuiCol_CheckMark: return "CheckMark";
3692 case ImGuiCol_SliderGrab: return "SliderGrab";
3693 case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
3694 case ImGuiCol_Button: return "Button";
3695 case ImGuiCol_ButtonHovered: return "ButtonHovered";
3696 case ImGuiCol_ButtonActive: return "ButtonActive";
3697 case ImGuiCol_Header: return "Header";
3698 case ImGuiCol_HeaderHovered: return "HeaderHovered";
3699 case ImGuiCol_HeaderActive: return "HeaderActive";
3700 case ImGuiCol_Separator: return "Separator";
3701 case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
3702 case ImGuiCol_SeparatorActive: return "SeparatorActive";
3703 case ImGuiCol_ResizeGrip: return "ResizeGrip";
3704 case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
3705 case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
3706 case ImGuiCol_InputTextCursor: return "InputTextCursor";
3707 case ImGuiCol_TabHovered: return "TabHovered";
3708 case ImGuiCol_Tab: return "Tab";
3709 case ImGuiCol_TabSelected: return "TabSelected";
3710 case ImGuiCol_TabSelectedOverline: return "TabSelectedOverline";
3711 case ImGuiCol_TabDimmed: return "TabDimmed";
3712 case ImGuiCol_TabDimmedSelected: return "TabDimmedSelected";
3713 case ImGuiCol_TabDimmedSelectedOverline: return "TabDimmedSelectedOverline";
3714 case ImGuiCol_DockingPreview: return "DockingPreview";
3715 case ImGuiCol_DockingEmptyBg: return "DockingEmptyBg";
3716 case ImGuiCol_PlotLines: return "PlotLines";
3717 case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
3718 case ImGuiCol_PlotHistogram: return "PlotHistogram";
3719 case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
3720 case ImGuiCol_TableHeaderBg: return "TableHeaderBg";
3721 case ImGuiCol_TableBorderStrong: return "TableBorderStrong";
3722 case ImGuiCol_TableBorderLight: return "TableBorderLight";
3723 case ImGuiCol_TableRowBg: return "TableRowBg";
3724 case ImGuiCol_TableRowBgAlt: return "TableRowBgAlt";
3725 case ImGuiCol_TextLink: return "TextLink";
3726 case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
3727 case ImGuiCol_TreeLines: return "TreeLines";
3728 case ImGuiCol_DragDropTarget: return "DragDropTarget";
3729 case ImGuiCol_NavCursor: return "NavCursor";
3730 case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
3731 case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg";
3732 case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg";
3733 }
3734 IM_ASSERT(0);
3735 return "Unknown";
3736}
3737
3738//-----------------------------------------------------------------------------
3739// [SECTION] RENDER HELPERS
3740// Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change,
3741// we need a nicer separation between low-level functions and high-level functions relying on the ImGui context.
3742// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context.
3743//-----------------------------------------------------------------------------
3744
3745const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
3746{
3747 const char* text_display_end = text;
3748 if (!text_end)
3749 text_end = (const char*)-1;
3750
3751 while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
3752 text_display_end++;
3753 return text_display_end;
3754}
3755
3756// Internal ImGui functions to render text
3757// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
3758void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
3759{
3760 ImGuiContext& g = *GImGui;
3761 ImGuiWindow* window = g.CurrentWindow;
3762
3763 // Hide anything after a '##' string
3764 const char* text_display_end;
3765 if (hide_text_after_hash)
3766 {
3767 text_display_end = FindRenderedTextEnd(text, text_end);
3768 }
3769 else
3770 {
3771 if (!text_end)
3772 text_end = text + ImStrlen(text); // FIXME-OPT
3773 text_display_end = text_end;
3774 }
3775
3776 if (text != text_display_end)
3777 {
3778 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
3779 if (g.LogEnabled)
3780 LogRenderedText(&pos, text, text_display_end);
3781 }
3782}
3783
3784void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
3785{
3786 ImGuiContext& g = *GImGui;
3787 ImGuiWindow* window = g.CurrentWindow;
3788
3789 if (!text_end)
3790 text_end = text + ImStrlen(text); // FIXME-OPT
3791
3792 if (text != text_end)
3793 {
3794 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
3795 if (g.LogEnabled)
3796 LogRenderedText(&pos, text, text_end);
3797 }
3798}
3799
3800// Default clip_rect uses (pos_min,pos_max)
3801// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
3802// FIXME-OPT: Since we have or calculate text_size we could coarse clip whole block immediately, especially for text above draw_list->DrawList.
3803// Effectively as this is called from widget doing their own coarse clipping it's not very valuable presently. Next time function will take
3804// better advantage of the render function taking size into account for coarse clipping.
3805void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
3806{
3807 // Perform CPU side clipping for single clipped element to avoid using scissor state
3808 ImVec2 pos = pos_min;
3809 const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
3810
3811 const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
3812 const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
3813 bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
3814 if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
3815 need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
3816
3817 // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
3818 if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
3819 if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
3820
3821 // Render
3822 if (need_clipping)
3823 {
3824 ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
3825 draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
3826 }
3827 else
3828 {
3829 draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
3830 }
3831}
3832
3833void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
3834{
3835 // Hide anything after a '##' string
3836 const char* text_display_end = FindRenderedTextEnd(text, text_end);
3837 const int text_len = (int)(text_display_end - text);
3838 if (text_len == 0)
3839 return;
3840
3841 ImGuiContext& g = *GImGui;
3842 ImGuiWindow* window = g.CurrentWindow;
3843 RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect);
3844 if (g.LogEnabled)
3845 LogRenderedText(&pos_min, text, text_display_end);
3846}
3847
3848// Another overly complex function until we reorganize everything into a nice all-in-one helper.
3849// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) from 'ellipsis_max_x' which may be beyond it.
3850// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.
3851// (BREAKING) On 2025/04/16 we removed the 'float clip_max_x' parameters which was preceeding 'float ellipsis_max' and was the same value for 99% of users.
3852void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)
3853{
3854 ImGuiContext& g = *GImGui;
3855 if (text_end_full == NULL)
3856 text_end_full = FindRenderedTextEnd(text);
3857 const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
3858
3859 //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 6), IM_COL32(0, 0, 255, 255));
3860 //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y - 2), ImVec2(ellipsis_max_x, pos_max.y + 3), IM_COL32(0, 255, 0, 255));
3861
3862 // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels.
3863 if (text_size.x > pos_max.x - pos_min.x)
3864 {
3865 // Hello wo...
3866 // | | |
3867 // min max ellipsis_max
3868 // <-> this is generally some padding value
3869
3870 ImFont* font = draw_list->_Data->Font;
3871 const float font_size = draw_list->_Data->FontSize;
3872 const float font_scale = draw_list->_Data->FontScale;
3873 const char* text_end_ellipsis = NULL;
3874 ImFontBaked* baked = font->GetFontBaked(font_size);
3875 const float ellipsis_width = baked->GetCharAdvance(font->EllipsisChar) * font_scale;
3876
3877 // We can now claim the space between pos_max.x and ellipsis_max.x
3878 const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f);
3879 float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
3880 while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
3881 {
3882 // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text)
3883 text_end_ellipsis--;
3884 text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte
3885 }
3886
3887 // Render text, render ellipsis
3888 RenderTextClippedEx(draw_list, pos_min, pos_max, text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
3889 ImVec4 cpu_fine_clip_rect(pos_min.x, pos_min.y, pos_max.x, pos_max.y);
3890 ImVec2 ellipsis_pos = ImTrunc(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y));
3891 font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar, &cpu_fine_clip_rect);
3892 }
3893 else
3894 {
3895 RenderTextClippedEx(draw_list, pos_min, pos_max, text, text_end_full, &text_size, ImVec2(0.0f, 0.0f));
3896 }
3897
3898 if (g.LogEnabled)
3899 LogRenderedText(&pos_min, text, text_end_full);
3900}
3901
3902// Render a rectangle shaped with optional rounding and borders
3903void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders, float rounding)
3904{
3905 ImGuiContext& g = *GImGui;
3906 ImGuiWindow* window = g.CurrentWindow;
3907 window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
3908 const float border_size = g.Style.FrameBorderSize;
3909 if (borders && border_size > 0.0f)
3910 {
3911 window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);
3912 window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
3913 }
3914}
3915
3916void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
3917{
3918 ImGuiContext& g = *GImGui;
3919 ImGuiWindow* window = g.CurrentWindow;
3920 const float border_size = g.Style.FrameBorderSize;
3921 if (border_size > 0.0f)
3922 {
3923 window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);
3924 window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
3925 }
3926}
3927
3929{
3930 ImGuiContext& g = *GImGui;
3931 if (id != g.NavId)
3932 return;
3934 return;
3936 return;
3937 ImGuiWindow* window = g.CurrentWindow;
3938 if (window->DC.NavHideHighlightOneFrame)
3939 return;
3940
3941 float rounding = (flags & ImGuiNavRenderCursorFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
3942 ImRect display_rect = bb;
3943 display_rect.ClipWith(window->ClipRect);
3944 const float thickness = 2.0f;
3946 {
3947 window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavCursor), rounding, 0, thickness);
3948 }
3949 else
3950 {
3951 const float distance = 3.0f + thickness * 0.5f;
3952 display_rect.Expand(ImVec2(distance, distance));
3953 bool fully_visible = window->ClipRect.Contains(display_rect);
3954 if (!fully_visible)
3955 window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
3956 window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavCursor), rounding, 0, thickness);
3957 if (!fully_visible)
3958 window->DrawList->PopClipRect();
3959 }
3960}
3961
3962void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
3963{
3964 ImGuiContext& g = *GImGui;
3965 if (mouse_cursor <= ImGuiMouseCursor_None || mouse_cursor >= ImGuiMouseCursor_COUNT) // We intentionally accept out of bound values.
3966 mouse_cursor = ImGuiMouseCursor_Arrow;
3968 for (ImGuiViewportP* viewport : g.Viewports)
3969 {
3970 // We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor.
3971 ImVec2 offset, size, uv[4];
3972 if (!ImFontAtlasGetMouseCursorTexData(font_atlas, mouse_cursor, &offset, &size, &uv[0], &uv[2]))
3973 continue;
3974 const ImVec2 pos = base_pos - offset;
3975 const float scale = base_scale * viewport->DpiScale;
3976 if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale)))
3977 continue;
3978 ImDrawList* draw_list = GetForegroundDrawList(viewport);
3979 ImTextureRef tex_ref = font_atlas->TexRef;
3980 draw_list->PushTexture(tex_ref);
3981 draw_list->AddImage(tex_ref, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow);
3982 draw_list->AddImage(tex_ref, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow);
3983 draw_list->AddImage(tex_ref, pos, pos + size * scale, uv[2], uv[3], col_border);
3984 draw_list->AddImage(tex_ref, pos, pos + size * scale, uv[0], uv[1], col_fill);
3985 if (mouse_cursor == ImGuiMouseCursor_Wait || mouse_cursor == ImGuiMouseCursor_Progress)
3986 {
3987 float a_min = ImFmod((float)g.Time * 5.0f, 2.0f * IM_PI);
3988 float a_max = a_min + IM_PI * 1.65f;
3989 draw_list->PathArcTo(pos + ImVec2(14, -1) * scale, 6.0f * scale, a_min, a_max);
3990 draw_list->PathStroke(col_fill, ImDrawFlags_None, 3.0f * scale);
3991 }
3992 draw_list->PopTexture();
3993 }
3994}
3995
3996//-----------------------------------------------------------------------------
3997// [SECTION] INITIALIZATION, SHUTDOWN
3998//-----------------------------------------------------------------------------
3999
4000// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself
4001// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module
4003{
4004 return GImGui;
4005}
4006
4008{
4009#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
4010 IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
4011#else
4012 GImGui = ctx;
4013#endif
4014}
4015
4016void ImGui::SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data)
4017{
4018 GImAllocatorAllocFunc = alloc_func;
4019 GImAllocatorFreeFunc = free_func;
4020 GImAllocatorUserData = user_data;
4021}
4022
4023// This is provided to facilitate copying allocators from one static/DLL boundary to another (e.g. retrieve default allocator of your executable address space)
4024void ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data)
4025{
4026 *p_alloc_func = GImAllocatorAllocFunc;
4027 *p_free_func = GImAllocatorFreeFunc;
4028 *p_user_data = GImAllocatorUserData;
4029}
4030
4032{
4033 ImGuiContext* prev_ctx = GetCurrentContext();
4034 ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
4035 SetCurrentContext(ctx);
4036 Initialize();
4037 if (prev_ctx != NULL)
4038 SetCurrentContext(prev_ctx); // Restore previous context if any, else keep new one.
4039 return ctx;
4040}
4041
4043{
4044 ImGuiContext* prev_ctx = GetCurrentContext();
4045 if (ctx == NULL) //-V1051
4046 ctx = prev_ctx;
4047 SetCurrentContext(ctx);
4048 Shutdown();
4049 SetCurrentContext((prev_ctx != ctx) ? prev_ctx : NULL);
4050 IM_DELETE(ctx);
4051}
4052
4053// IMPORTANT: interactive elements requires a fixed ###xxx suffix, it must be same in ALL languages to allow for automation.
4055{
4057 { ImGuiLocKey_TableSizeOne, "Size column to fit###SizeOne" },
4058 { ImGuiLocKey_TableSizeAllFit, "Size all columns to fit###SizeAll" },
4059 { ImGuiLocKey_TableSizeAllDefault, "Size all columns to default###SizeAll" },
4060 { ImGuiLocKey_TableResetOrder, "Reset order###ResetOrder" },
4061 { ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" },
4062 { ImGuiLocKey_WindowingPopup, "(Popup)" },
4063 { ImGuiLocKey_WindowingUntitled, "(Untitled)" },
4064 { ImGuiLocKey_OpenLink_s, "Open '%s'" },
4065 { ImGuiLocKey_CopyLink, "Copy Link###CopyLink" },
4066 { ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" },
4067 { ImGuiLocKey_DockingHoldShiftToDock, "Hold SHIFT to enable Docking window." },
4068 { ImGuiLocKey_DockingDragToUndockOrMoveNode,"Click and drag to move or undock whole node." },
4069};
4070
4072{
4073 IO.Ctx = this;
4074 InputTextState.Ctx = this;
4075
4076 Initialized = false;
4077 ConfigFlagsCurrFrame = ConfigFlagsLastFrame = ImGuiConfigFlags_None;
4078
4079 Font = NULL;
4080 FontBaked = NULL;
4081 FontSize = FontSizeBase = FontBakedScale = CurrentDpiScale = 0.0f;
4082 FontRasterizerDensity = 1.0f;
4083 IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
4084 if (shared_font_atlas == NULL)
4085 IO.Fonts->OwnerContext = this;
4086 Time = 0.0f;
4087 FrameCount = 0;
4088 FrameCountEnded = FrameCountPlatformEnded = FrameCountRendered = -1;
4089 WithinEndChildID = 0;
4090 WithinFrameScope = WithinFrameScopeWithImplicitWindow = false;
4091 GcCompactAll = false;
4092 TestEngineHookItems = false;
4093 TestEngine = NULL;
4094 memset(ContextName, 0, sizeof(ContextName));
4095
4096 InputEventsNextMouseSource = ImGuiMouseSource_Mouse;
4097 InputEventsNextEventId = 1;
4098
4099 WindowsActiveCount = 0;
4100 WindowsBorderHoverPadding = 0.0f;
4101 CurrentWindow = NULL;
4102 HoveredWindow = NULL;
4103 HoveredWindowUnderMovingWindow = NULL;
4104 HoveredWindowBeforeClear = NULL;
4105 MovingWindow = NULL;
4106 WheelingWindow = NULL;
4107 WheelingWindowStartFrame = WheelingWindowScrolledFrame = -1;
4108 WheelingWindowReleaseTimer = 0.0f;
4109
4110 DebugDrawIdConflictsId = 0;
4111 DebugHookIdInfo = 0;
4112 HoveredId = HoveredIdPreviousFrame = 0;
4113 HoveredIdPreviousFrameItemCount = 0;
4114 HoveredIdAllowOverlap = false;
4115 HoveredIdIsDisabled = false;
4116 HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;
4117 ItemUnclipByLog = false;
4118 ActiveId = 0;
4119 ActiveIdIsAlive = 0;
4120 ActiveIdTimer = 0.0f;
4121 ActiveIdIsJustActivated = false;
4122 ActiveIdAllowOverlap = false;
4123 ActiveIdNoClearOnFocusLoss = false;
4124 ActiveIdHasBeenPressedBefore = false;
4125 ActiveIdHasBeenEditedBefore = false;
4126 ActiveIdHasBeenEditedThisFrame = false;
4127 ActiveIdFromShortcut = false;
4128 ActiveIdClickOffset = ImVec2(-1, -1);
4129 ActiveIdWindow = NULL;
4130 ActiveIdSource = ImGuiInputSource_None;
4131 ActiveIdMouseButton = -1;
4132 ActiveIdPreviousFrame = 0;
4133 memset(&DeactivatedItemData, 0, sizeof(DeactivatedItemData));
4134 memset(&ActiveIdValueOnActivation, 0, sizeof(ActiveIdValueOnActivation));
4135 LastActiveId = 0;
4136 LastActiveIdTimer = 0.0f;
4137
4138 LastKeyboardKeyPressTime = LastKeyModsChangeTime = LastKeyModsChangeFromNoneTime = -1.0;
4139
4140 ActiveIdUsingNavDirMask = 0x00;
4141 ActiveIdUsingAllKeyboardKeys = false;
4142
4143 CurrentFocusScopeId = 0;
4144 CurrentItemFlags = ImGuiItemFlags_None;
4145 DebugShowGroupRects = false;
4146
4147 CurrentViewport = NULL;
4148 MouseViewport = MouseLastHoveredViewport = NULL;
4149 PlatformLastFocusedViewportId = 0;
4150 ViewportCreatedCount = PlatformWindowsCreatedCount = 0;
4151 ViewportFocusedStampCount = 0;
4152
4153 NavCursorVisible = false;
4154 NavHighlightItemUnderNav = false;
4155 NavMousePosDirty = false;
4156 NavIdIsAlive = false;
4157 NavId = 0;
4158 NavWindow = NULL;
4159 NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0;
4160 NavLayer = ImGuiNavLayer_Main;
4161 NavNextActivateId = 0;
4162 NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None;
4163 NavHighlightActivatedId = 0;
4164 NavHighlightActivatedTimer = 0.0f;
4165 NavInputSource = ImGuiInputSource_Keyboard;
4166 NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
4167 NavCursorHideFrames = 0;
4168
4169 NavAnyRequest = false;
4170 NavInitRequest = false;
4171 NavInitRequestFromMove = false;
4172 NavMoveSubmitted = false;
4173 NavMoveScoringItems = false;
4174 NavMoveForwardToNextFrame = false;
4175 NavMoveFlags = ImGuiNavMoveFlags_None;
4176 NavMoveScrollFlags = ImGuiScrollFlags_None;
4177 NavMoveKeyMods = ImGuiMod_None;
4178 NavMoveDir = NavMoveDirForDebug = NavMoveClipDir = ImGuiDir_None;
4179 NavScoringDebugCount = 0;
4180 NavTabbingDir = 0;
4181 NavTabbingCounter = 0;
4182
4183 NavJustMovedFromFocusScopeId = NavJustMovedToId = NavJustMovedToFocusScopeId = 0;
4184 NavJustMovedToKeyMods = ImGuiMod_None;
4185 NavJustMovedToIsTabbing = false;
4186 NavJustMovedToHasSelectionData = false;
4187
4188 // All platforms use Ctrl+Tab but Ctrl<>Super are swapped on Mac...
4189 // FIXME: Because this value is stored, it annoyingly interfere with toggling io.ConfigMacOSXBehaviors updating this..
4190 ConfigNavWindowingWithGamepad = true;
4191 ConfigNavWindowingKeyNext = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiKey_Tab);
4192 ConfigNavWindowingKeyPrev = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiMod_Shift | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab);
4193 NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL;
4194 NavWindowingInputSource = ImGuiInputSource_None;
4195 NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f;
4196 NavWindowingToggleLayer = false;
4197 NavWindowingToggleKey = ImGuiKey_None;
4198
4199 DimBgRatio = 0.0f;
4200
4201 DragDropActive = DragDropWithinSource = DragDropWithinTarget = false;
4202 DragDropSourceFlags = ImGuiDragDropFlags_None;
4203 DragDropSourceFrameCount = -1;
4204 DragDropMouseButton = -1;
4205 DragDropTargetId = 0;
4206 DragDropAcceptFlags = ImGuiDragDropFlags_None;
4207 DragDropAcceptIdCurrRectSurface = 0.0f;
4208 DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0;
4209 DragDropAcceptFrameCount = -1;
4210 DragDropHoldJustPressedId = 0;
4211 memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal));
4212
4213 ClipperTempDataStacked = 0;
4214
4215 CurrentTable = NULL;
4216 TablesTempDataStacked = 0;
4217 CurrentTabBar = NULL;
4218 CurrentMultiSelect = NULL;
4219 MultiSelectTempDataStacked = 0;
4220
4221 HoverItemDelayId = HoverItemDelayIdPreviousFrame = HoverItemUnlockedStationaryId = HoverWindowUnlockedStationaryId = 0;
4222 HoverItemDelayTimer = HoverItemDelayClearTimer = 0.0f;
4223
4224 MouseCursor = ImGuiMouseCursor_Arrow;
4225 MouseStationaryTimer = 0.0f;
4226
4227 InputTextPasswordFontBackupFlags = ImFontFlags_None;
4228 TempInputId = 0;
4229 memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue));
4230 BeginMenuDepth = BeginComboDepth = 0;
4231 ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_;
4232 ColorEditCurrentID = ColorEditSavedID = 0;
4233 ColorEditSavedHue = ColorEditSavedSat = 0.0f;
4234 ColorEditSavedColor = 0;
4235 WindowResizeRelativeMode = false;
4236 ScrollbarSeekMode = 0;
4237 ScrollbarClickDeltaToGrabCenter = 0.0f;
4238 SliderGrabClickOffset = 0.0f;
4239 SliderCurrentAccum = 0.0f;
4240 SliderCurrentAccumDirty = false;
4241 DragCurrentAccumDirty = false;
4242 DragCurrentAccum = 0.0f;
4243 DragSpeedDefaultRatio = 1.0f / 100.0f;
4244 DisabledAlphaBackup = 0.0f;
4245 DisabledStackSize = 0;
4246 TooltipOverrideCount = 0;
4247 TooltipPreviousWindow = NULL;
4248
4249 PlatformImeData.InputPos = ImVec2(0.0f, 0.0f);
4250 PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission
4251
4252 DockNodeWindowMenuHandler = NULL;
4253
4254 SettingsLoaded = false;
4255 SettingsDirtyTimer = 0.0f;
4256 HookIdNext = 0;
4257
4258 memset(LocalizationTable, 0, sizeof(LocalizationTable));
4259
4260 LogEnabled = false;
4261 LogFlags = ImGuiLogFlags_None;
4262 LogWindow = NULL;
4263 LogNextPrefix = LogNextSuffix = NULL;
4264 LogFile = NULL;
4265 LogLinePosY = FLT_MAX;
4266 LogLineFirstItem = false;
4267 LogDepthRef = 0;
4268 LogDepthToExpand = LogDepthToExpandDefault = 2;
4269
4270 ErrorCallback = NULL;
4271 ErrorCallbackUserData = NULL;
4272 ErrorFirst = true;
4273 ErrorCountCurrentFrame = 0;
4274 StackSizesInBeginForCurrentWindow = NULL;
4275
4276 DebugDrawIdConflictsCount = 0;
4278 DebugLocateId = 0;
4279 DebugLogSkippedErrors = 0;
4280 DebugLogAutoDisableFlags = ImGuiDebugLogFlags_None;
4281 DebugLogAutoDisableFrames = 0;
4282 DebugLocateFrames = 0;
4283 DebugBeginReturnValueCullDepth = -1;
4284 DebugItemPickerActive = false;
4285 DebugItemPickerMouseButton = ImGuiMouseButton_Left;
4286 DebugItemPickerBreakId = 0;
4287 DebugFlashStyleColorTime = 0.0f;
4288 DebugFlashStyleColorIdx = ImGuiCol_COUNT;
4289 DebugHoveredDockNode = NULL;
4290
4291 // Same as DebugBreakClearData(). Those fields are scattered in their respective subsystem to stay in hot-data locations
4292 DebugBreakInWindow = 0;
4293 DebugBreakInTable = 0;
4294 DebugBreakInLocateId = false;
4295 DebugBreakKeyChord = ImGuiKey_Pause;
4296 DebugBreakInShortcutRouting = ImGuiKey_None;
4297
4298 memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame));
4299 FramerateSecPerFrameIdx = FramerateSecPerFrameCount = 0;
4300 FramerateSecPerFrameAccum = 0.0f;
4301 WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1;
4302 memset(TempKeychordName, 0, sizeof(TempKeychordName));
4303}
4304
4306{
4307 ImGuiContext& g = *GImGui;
4309
4310 // Add .ini handle for ImGuiWindow and ImGuiTable types
4311 {
4312 ImGuiSettingsHandler ini_handler;
4313 ini_handler.TypeName = "Window";
4314 ini_handler.TypeHash = ImHashStr("Window");
4320 AddSettingsHandler(&ini_handler);
4321 }
4323
4324 // Setup default localization table
4326
4327 // Setup default ImGuiPlatformIO clipboard/IME handlers.
4328 g.PlatformIO.Platform_GetClipboardTextFn = Platform_GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
4332
4333 // Create default viewport
4334 ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
4335 viewport->ID = IMGUI_VIEWPORT_DEFAULT_ID;
4336 viewport->Idx = 0;
4337 viewport->PlatformWindowCreated = true;
4339 g.Viewports.push_back(viewport);
4340 g.TempBuffer.resize(1024 * 3 + 1, 0);
4343
4344 // Build KeysMayBeCharInput[] lookup table (1 bool per named key)
4345 for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
4346 if ((key >= ImGuiKey_0 && key <= ImGuiKey_9) || (key >= ImGuiKey_A && key <= ImGuiKey_Z) || (key >= ImGuiKey_Keypad0 && key <= ImGuiKey_Keypad9)
4347 || key == ImGuiKey_Tab || key == ImGuiKey_Space || key == ImGuiKey_Apostrophe || key == ImGuiKey_Comma || key == ImGuiKey_Minus || key == ImGuiKey_Period
4351
4352#ifdef IMGUI_HAS_DOCK
4353 // Initialize Docking
4355#endif
4356
4357 // Print a debug message when running with debug feature IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS because it is very slow.
4358 // DO NOT COMMENT OUT THIS MESSAGE. IT IS DESIGNED TO REMIND YOU THAT IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS SHOULD ONLY BE TEMPORARILY ENABLED.
4359#ifdef IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
4360 DebugLog("IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS is enabled.\nMust disable after use! Otherwise Dear ImGui will run slower.\n");
4361#endif
4362
4363 // ImDrawList/ImFontAtlas are designed to function without ImGui, and 99% of it works without an ImGui context.
4364 // But this link allows us to facilitate/handle a few edge cases better.
4365 ImFontAtlas* atlas = g.IO.Fonts;
4367 RegisterFontAtlas(atlas);
4368
4369 g.Initialized = true;
4370}
4371
4372// This function is merely here to free heap allocations.
4374{
4375 ImGuiContext& g = *GImGui;
4376 IM_ASSERT_USER_ERROR(g.IO.BackendPlatformUserData == NULL, "Forgot to shutdown Platform backend?");
4377 IM_ASSERT_USER_ERROR(g.IO.BackendRendererUserData == NULL, "Forgot to shutdown Renderer backend?");
4378
4379 // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame)
4380 for (ImFontAtlas* atlas : g.FontAtlases)
4381 {
4382 UnregisterFontAtlas(atlas);
4383 if (atlas->OwnerContext == &g)
4384 {
4385 atlas->Locked = false;
4386 IM_DELETE(atlas);
4387 }
4388 }
4390
4391 // Cleanup of other data are conditional on actually having initialized Dear ImGui.
4392 if (!g.Initialized)
4393 return;
4394
4395 // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
4396 if (g.SettingsLoaded && g.IO.IniFilename != NULL)
4398
4399 // Destroy platform windows
4401
4402 // Shutdown extensions
4404
4406
4407 // Clear everything else
4411 g.CurrentWindow = NULL;
4413 g.WindowsById.Clear();
4414 g.NavWindow = NULL;
4416 g.ActiveIdWindow = NULL;
4417 g.MovingWindow = NULL;
4418
4420
4421 g.ColorStack.clear();
4422 g.StyleVarStack.clear();
4423 g.FontStack.clear();
4426 g.TreeNodeStack.clear();
4427
4430
4431 g.TabBars.Clear();
4434
4436
4437 g.Tables.Clear();
4440
4443
4448
4451
4452 if (g.LogFile)
4453 {
4454#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
4455 if (g.LogFile != stdout)
4456#endif
4458 g.LogFile = NULL;
4459 }
4460 g.LogBuffer.clear();
4461 g.DebugLogBuf.clear();
4462 g.DebugLogIndex.clear();
4463
4464 g.Initialized = false;
4465}
4466
4467// No specific ordering/dependency support, will see as needed
4469{
4470 ImGuiContext& g = *ctx;
4471 IM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_);
4472 g.Hooks.push_back(*hook);
4473 g.Hooks.back().HookId = ++g.HookIdNext;
4474 return g.HookIdNext;
4475}
4476
4477// Deferred removal, avoiding issue with changing vector while iterating it
4479{
4480 ImGuiContext& g = *ctx;
4481 IM_ASSERT(hook_id != 0);
4482 for (ImGuiContextHook& hook : g.Hooks)
4483 if (hook.HookId == hook_id)
4485}
4486
4487// Call context hooks (used by e.g. test engine)
4488// We assume a small number of hooks so all stored in same array
4490{
4491 ImGuiContext& g = *ctx;
4492 for (ImGuiContextHook& hook : g.Hooks)
4493 if (hook.Type == hook_type)
4494 hook.Callback(&g, &hook);
4495}
4496
4497//-----------------------------------------------------------------------------
4498// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
4499//-----------------------------------------------------------------------------
4500
4501// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods
4502ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NULL)
4503{
4504 memset(this, 0, sizeof(*this));
4505 Ctx = ctx;
4506 Name = ImStrdup(name);
4507 NameBufLen = (int)ImStrlen(name) + 1;
4508 ID = ImHashStr(name);
4511 ViewportPos = ImVec2(FLT_MAX, FLT_MAX);
4512 MoveId = GetID("#MOVE");
4513 TabId = GetID("#TAB");
4514 ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
4515 ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
4519 SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
4520 LastFrameActive = -1;
4522 LastTimeActive = -1.0f;
4523 FontRefSize = 0.0f;
4525 SettingsOffset = -1;
4526 DockOrder = -1;
4532}
4533
4535{
4537 IM_DELETE(Name);
4539}
4540
4541static void SetCurrentWindow(ImGuiWindow* window)
4542{
4543 ImGuiContext& g = *GImGui;
4544 g.CurrentWindow = window;
4546 g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL;
4547 if (window)
4548 {
4549 bool backup_skip_items = window->SkipItems;
4550 window->SkipItems = false;
4552 {
4553 ImGuiViewport* viewport = window->Viewport;
4554 g.FontRasterizerDensity = (viewport->FramebufferScale.x != 0.0f) ? viewport->FramebufferScale.x : g.IO.DisplayFramebufferScale.x; // == SetFontRasterizerDensity()
4555 }
4557 window->SkipItems = backup_skip_items;
4559 }
4560}
4561
4563{
4564 ImGuiContext& g = *GImGui;
4566 g.GroupStack.clear();
4570 for (ImFontAtlas* atlas : g.FontAtlases)
4571 atlas->CompactCache();
4572}
4573
4574// Free up/compact internal window buffers, we can use this when a window becomes unused.
4575// Not freed:
4576// - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data)
4577// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost.
4579{
4580 window->MemoryCompacted = true;
4583 window->IDStack.clear();
4584 window->DrawList->_ClearFreeMemory();
4585 window->DC.ChildWindows.clear();
4586 window->DC.ItemWidthStack.clear();
4587 window->DC.TextWrapPosStack.clear();
4588}
4589
4591{
4592 // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening.
4593 // The other buffers tends to amortize much faster.
4594 window->MemoryCompacted = false;
4598}
4599
4601{
4602 ImGuiContext& g = *GImGui;
4603
4604 // Clear previous active id
4605 if (g.ActiveId != 0)
4606 {
4607 // While most behaved code would make an effort to not steal active id during window move/drag operations,
4608 // we at least need to be resilient to it. Canceling the move is rather aggressive and users of 'master' branch
4609 // may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that.
4610 if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId)
4611 {
4612 IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n");
4613 g.MovingWindow = NULL;
4614 }
4615
4616 // Store deactivate data
4617 ImGuiDeactivatedItemData* deactivated_data = &g.DeactivatedItemData;
4618 deactivated_data->ID = g.ActiveId;
4619 deactivated_data->ElapseFrame = (g.LastItemData.ID == g.ActiveId) ? g.FrameCount : g.FrameCount + 1; // FIXME: OK to use LastItemData?
4621 deactivated_data->IsAlive = (g.ActiveIdIsAlive == g.ActiveId);
4622
4623 // This could be written in a more general way (e.g associate a hook to ActiveId),
4624 // but since this is currently quite an exception we'll leave it as is.
4625 // One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveID()
4626 if (g.InputTextState.ID == g.ActiveId)
4628 }
4629
4630 // Set active id
4631 g.ActiveIdIsJustActivated = (g.ActiveId != id);
4633 {
4634 IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() old:0x%08X (window \"%s\") -> new:0x%08X (window \"%s\")\n", g.ActiveId, g.ActiveIdWindow ? g.ActiveIdWindow->Name : "", id, window ? window->Name : "");
4635 g.ActiveIdTimer = 0.0f;
4638 g.ActiveIdMouseButton = -1;
4639 if (id != 0)
4640 {
4641 g.LastActiveId = id;
4642 g.LastActiveIdTimer = 0.0f;
4643 }
4644 }
4645 g.ActiveId = id;
4646 g.ActiveIdAllowOverlap = false;
4648 g.ActiveIdWindow = window;
4650 g.ActiveIdFromShortcut = false;
4651 if (id)
4652 {
4653 g.ActiveIdIsAlive = id;
4656 }
4657
4658 // Clear declaration of inputs claimed by the widget
4659 // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet)
4660 g.ActiveIdUsingNavDirMask = 0x00;
4662}
4663
4665{
4666 SetActiveID(0, NULL); // g.ActiveId = 0;
4667}
4668
4670{
4671 ImGuiContext& g = *GImGui;
4672 g.HoveredId = id;
4673 g.HoveredIdAllowOverlap = false;
4674 if (id != 0 && g.HoveredIdPreviousFrame != id)
4676}
4677
4679{
4680 ImGuiContext& g = *GImGui;
4682}
4683
4685{
4686 // This marking is to be able to provide info for IsItemDeactivatedAfterEdit().
4687 // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data.
4688 ImGuiContext& g = *GImGui;
4690 return;
4691 if (g.ActiveId == id || g.ActiveId == 0)
4692 {
4693 // FIXME: Can't we fully rely on LastItemData yet?
4696 if (g.DeactivatedItemData.ID == id)
4698 }
4699
4700 // We accept a MarkItemEdited() on drag and drop targets (see https://github.com/ocornut/imgui/issues/1875#issuecomment-978243343)
4701 // We accept 'ActiveIdPreviousFrame == id' for InputText() returning an edit after it has been taken ActiveId away (#4714)
4702 IM_ASSERT(g.DragDropActive || g.ActiveId == id || g.ActiveId == 0 || g.ActiveIdPreviousFrame == id || (g.CurrentMultiSelect != NULL && g.BoxSelectState.IsActive));
4703
4704 //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
4706}
4707
4709{
4710 // An active popup disable hovering on other windows (apart from its own children)
4711 // FIXME-OPT: This could be cached/stored within the window.
4712 ImGuiContext& g = *GImGui;
4713 if (g.NavWindow)
4714 if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindowDockTree)
4715 if (focused_root_window->WasActive && focused_root_window != window->RootWindowDockTree)
4716 {
4717 // For the purpose of those flags we differentiate "standard popup" from "modal popup"
4718 // NB: The 'else' is important because Modal windows are also Popups.
4719 bool want_inhibit = false;
4720 if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
4721 want_inhibit = true;
4722 else if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
4723 want_inhibit = true;
4724
4725 // Inhibit hover unless the window is within the stack of our modal/popup
4726 if (want_inhibit)
4727 if (!IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window))
4728 return false;
4729 }
4730
4731 // Filter by viewport
4732 if (window->Viewport != g.MouseViewport)
4733 if (g.MovingWindow == NULL || window->RootWindowDockTree != g.MovingWindow->RootWindowDockTree)
4734 return false;
4735
4736 return true;
4737}
4738
4740{
4741 ImGuiContext& g = *GImGui;
4743 return g.Style.HoverDelayNormal;
4744 if (flags & ImGuiHoveredFlags_DelayShort)
4745 return g.Style.HoverDelayShort;
4746 return 0.0f;
4747}
4748
4750{
4751 // Allow instance flags to override shared flags
4754 return user_flags | shared_flags;
4755}
4756
4757// This is roughly matching the behavior of internal-facing ItemHoverable()
4758// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered()
4759// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
4761{
4762 ImGuiContext& g = *GImGui;
4763 ImGuiWindow* window = g.CurrentWindow;
4764 IM_ASSERT_USER_ERROR((flags & ~ImGuiHoveredFlags_AllowedMaskForIsItemHovered) == 0, "Invalid flags for IsItemHovered()!");
4765
4767 {
4768 if (!IsItemFocused())
4769 return false;
4771 return false;
4772
4773 if (flags & ImGuiHoveredFlags_ForTooltip)
4775 }
4776 else
4777 {
4778 // Test for bounding box overlap, as updated as ItemAdd()
4780 if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
4781 return false;
4782
4783 if (flags & ImGuiHoveredFlags_ForTooltip)
4785
4786 // Done with rectangle culling so we can perform heavier checks now
4787 // Test if we are hovering the right window (our window could be behind another window)
4788 // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)
4789 // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable
4790 // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was
4791 // the test that has been running for a long while.
4792 if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0)
4794 return false;
4795
4796 // Test if another item is active (e.g. being dragged)
4797 const ImGuiID id = g.LastItemData.ID;
4799 if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
4800 if (g.ActiveId != window->MoveId && g.ActiveId != window->TabId)
4801 return false;
4802
4803 // Test if interactions on this window are blocked by an active popup or modal.
4804 // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
4806 return false;
4807
4808 // Test if the item is disabled
4810 return false;
4811
4812 // Special handling for calling after Begin() which represent the title bar or tab.
4813 // When the window is skipped/collapsed (SkipItems==true) that last item (always ->MoveId submitted by Begin)
4814 // will never be overwritten so we need to detect the case.
4815 if (id == window->MoveId && window->WriteAccessed)
4816 return false;
4817
4818 // Test if using AllowOverlap and overlapped
4822 return false;
4823 }
4824
4825 // Handle hover delay
4826 // (some ideas: https://www.nngroup.com/articles/timing-exposing-content)
4827 const float delay = CalcDelayFromHoveredFlags(flags);
4828 if (delay > 0.0f || (flags & ImGuiHoveredFlags_Stationary))
4829 {
4830 ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromPos(g.LastItemData.Rect.Min);
4831 if ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverItemDelayIdPreviousFrame != hover_delay_id))
4832 g.HoverItemDelayTimer = 0.0f;
4833 g.HoverItemDelayId = hover_delay_id;
4834
4835 // When changing hovered item we requires a bit of stationary delay before activating hover timer,
4836 // but once unlocked on a given item we also moving.
4837 //if (g.HoverDelayTimer >= delay && (g.HoverDelayTimer - g.IO.DeltaTime < delay || g.MouseStationaryTimer - g.IO.DeltaTime < g.Style.HoverStationaryDelay)) { IMGUI_DEBUG_LOG("HoverDelayTimer = %f/%f, MouseStationaryTimer = %f\n", g.HoverDelayTimer, delay, g.MouseStationaryTimer); }
4838 if ((flags & ImGuiHoveredFlags_Stationary) != 0 && g.HoverItemUnlockedStationaryId != hover_delay_id)
4839 return false;
4840
4841 if (g.HoverItemDelayTimer < delay)
4842 return false;
4843 }
4844
4845 return true;
4846}
4847
4848// Internal facing ItemHoverable() used when submitting widgets. THIS IS A SUBMISSION NOT A HOVER CHECK.
4849// Returns whether the item was hovered, logic differs slightly from IsItemHovered().
4850// (this does not rely on LastItemData it can be called from a ButtonBehavior() call not following an ItemAdd() call)
4851// FIXME-LEGACY: the 'ImGuiItemFlags item_flags' parameter was added on 2023-06-28.
4852// If you used this in your legacy/custom widgets code:
4853// - Commonly: if your ItemHoverable() call comes after an ItemAdd() call: pass 'item_flags = g.LastItemData.ItemFlags'.
4854// - Rare: otherwise you may pass 'item_flags = 0' (ImGuiItemFlags_None) unless you want to benefit from special behavior handled by ItemHoverable.
4855bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags)
4856{
4857 ImGuiContext& g = *GImGui;
4858 ImGuiWindow* window = g.CurrentWindow;
4859
4860 // Detect ID conflicts
4861 // (this is specifically done here by comparing on hover because it allows us a detection of duplicates that is algorithmically extra cheap, 1 u32 compare per item. No O(log N) lookup whatsoever)
4862#ifndef IMGUI_DISABLE_DEBUG_TOOLS
4863 if (id != 0 && g.HoveredIdPreviousFrame == id && (item_flags & ImGuiItemFlags_AllowDuplicateId) == 0)
4864 {
4866 if (g.DebugDrawIdConflictsId == id)
4867 window->DrawList->AddRect(bb.Min - ImVec2(1,1), bb.Max + ImVec2(1,1), IM_COL32(255, 0, 0, 255), 0.0f, ImDrawFlags_None, 2.0f);
4868 }
4869#endif
4870
4871 if (g.HoveredWindow != window)
4872 return false;
4873 if (!IsMouseHoveringRect(bb.Min, bb.Max))
4874 return false;
4875
4876 if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
4877 return false;
4878 if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
4879 if (!g.ActiveIdFromShortcut)
4880 return false;
4881
4882 // Done with rectangle culling so we can perform heavier checks now.
4884 {
4885 g.HoveredIdIsDisabled = true;
4886 return false;
4887 }
4888
4889 // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level
4890 // hover test in widgets code. We could also decide to split this function is two.
4891 if (id != 0)
4892 {
4893 // Drag source doesn't report as hovered
4895 return false;
4896
4897 SetHoveredID(id);
4898
4899 // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match.
4900 // This allows using patterns where a later submitted widget overlaps a previous one. Generally perceived as a front-to-back hit-test.
4901 if (item_flags & ImGuiItemFlags_AllowOverlap)
4902 {
4903 g.HoveredIdAllowOverlap = true;
4904 if (g.HoveredIdPreviousFrame != id)
4905 return false;
4906 }
4907
4908 // Display shortcut (only works with mouse)
4909 // (ImGuiItemStatusFlags_HasShortcut in LastItemData denotes we want a tooltip)
4913 }
4914
4915 // When disabled we'll return false but still set HoveredId
4916 if (item_flags & ImGuiItemFlags_Disabled)
4917 {
4918 // Release active id if turning disabled
4919 if (g.ActiveId == id && id != 0)
4920 ClearActiveID();
4921 g.HoveredIdIsDisabled = true;
4922 return false;
4923 }
4924
4925#ifndef IMGUI_DISABLE_DEBUG_TOOLS
4926 if (id != 0)
4927 {
4928 // [DEBUG] Item Picker tool!
4929 // We perform the check here because reaching is path is rare (1~ time a frame),
4930 // making the cost of this tool near-zero! We could get better call-stack and support picking non-hovered
4931 // items if we performed the test in ItemAdd(), but that would incur a bigger runtime cost.
4933 GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255));
4934 if (g.DebugItemPickerBreakId == id)
4936 }
4937#endif
4938
4940 return false;
4941
4942 return true;
4943}
4944
4945// FIXME: This is inlined/duplicated in ItemAdd()
4946// FIXME: The id != 0 path is not used by our codebase, may get rid of it?
4948{
4949 ImGuiContext& g = *GImGui;
4950 ImGuiWindow* window = g.CurrentWindow;
4951 if (!bb.Overlaps(window->ClipRect))
4952 if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId && id != g.NavActivateId))
4953 if (!g.ItemUnclipByLog)
4954 return true;
4955 return false;
4956}
4957
4958// This is also inlined in ItemAdd()
4959// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set g.LastItemData.DisplayRect.
4960void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags item_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect)
4961{
4962 ImGuiContext& g = *GImGui;
4963 g.LastItemData.ID = item_id;
4964 g.LastItemData.ItemFlags = item_flags;
4965 g.LastItemData.StatusFlags = status_flags;
4966 g.LastItemData.Rect = g.LastItemData.NavRect = item_rect;
4967}
4968
4969static void ImGui::SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect)
4970{
4971 ImGuiContext& g = *GImGui;
4972 if (window->DockIsActive)
4974 else
4976}
4977
4979{
4980 ImGuiContext& g = *GImGui;
4982}
4983
4984float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
4985{
4986 if (wrap_pos_x < 0.0f)
4987 return 0.0f;
4988
4989 ImGuiContext& g = *GImGui;
4990 ImGuiWindow* window = g.CurrentWindow;
4991 if (wrap_pos_x == 0.0f)
4992 {
4993 // We could decide to setup a default wrapping max point for auto-resizing windows,
4994 // or have auto-wrap (with unspecified wrapping pos) behave as a ContentSize extending function?
4995 //if (window->Hidden && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize))
4996 // wrap_pos_x = ImMax(window->WorkRect.Min.x + g.FontSize * 10.0f, window->WorkRect.Max.x);
4997 //else
4998 wrap_pos_x = window->WorkRect.Max.x;
4999 }
5000 else if (wrap_pos_x > 0.0f)
5001 {
5002 wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
5003 }
5004
5005 return ImMax(wrap_pos_x - pos.x, 1.0f);
5006}
5007
5008// IM_ALLOC() == ImGui::MemAlloc()
5009void* ImGui::MemAlloc(size_t size)
5010{
5011 void* ptr = (*GImAllocatorAllocFunc)(size, GImAllocatorUserData);
5012#ifndef IMGUI_DISABLE_DEBUG_TOOLS
5013 if (ImGuiContext* ctx = GImGui)
5014 DebugAllocHook(&ctx->DebugAllocInfo, ctx->FrameCount, ptr, size);
5015#endif
5016 return ptr;
5017}
5018
5019// IM_FREE() == ImGui::MemFree()
5020void ImGui::MemFree(void* ptr)
5021{
5022#ifndef IMGUI_DISABLE_DEBUG_TOOLS
5023 if (ptr != NULL)
5024 if (ImGuiContext* ctx = GImGui)
5025 DebugAllocHook(&ctx->DebugAllocInfo, ctx->FrameCount, ptr, (size_t)-1);
5026#endif
5028}
5029
5030// We record the number of allocation in recent frames, as a way to audit/sanitize our guiding principles of "no allocations on idle/repeating frames"
5031void ImGui::DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size)
5032{
5033 ImGuiDebugAllocEntry* entry = &info->LastEntriesBuf[info->LastEntriesIdx];
5034 IM_UNUSED(ptr);
5035 if (entry->FrameCount != frame_count)
5036 {
5037 info->LastEntriesIdx = (info->LastEntriesIdx + 1) % IM_ARRAYSIZE(info->LastEntriesBuf);
5038 entry = &info->LastEntriesBuf[info->LastEntriesIdx];
5039 entry->FrameCount = frame_count;
5040 entry->AllocCount = entry->FreeCount = 0;
5041 }
5042 if (size != (size_t)-1)
5043 {
5044 //printf("[%05d] MemAlloc(%d) -> 0x%p\n", frame_count, (int)size, ptr);
5045 entry->AllocCount++;
5046 info->TotalAllocCount++;
5047 }
5048 else
5049 {
5050 //printf("[%05d] MemFree(0x%p)\n", frame_count, ptr);
5051 entry->FreeCount++;
5052 info->TotalFreeCount++;
5053 }
5054}
5055
5057{
5058 ImGuiContext& g = *GImGui;
5060}
5061
5062void ImGui::SetClipboardText(const char* text)
5063{
5064 ImGuiContext& g = *GImGui;
5067}
5068
5070{
5071 return IMGUI_VERSION;
5072}
5073
5075{
5076 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
5077 return GImGui->IO;
5078}
5079
5080// This variant exists to facilitate backends experimenting with multi-threaded parallel context. (#8069, #6293, #5856)
5082{
5083 IM_ASSERT(ctx != NULL);
5084 return ctx->IO;
5085}
5086
5088{
5089 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext()?");
5090 return GImGui->PlatformIO;
5091}
5092
5093// This variant exists to facilitate backends experimenting with multi-threaded parallel context. (#8069, #6293, #5856)
5095{
5096 IM_ASSERT(ctx != NULL);
5097 return ctx->PlatformIO;
5098}
5099
5100// Pass this to your backend rendering function! Valid after Render() and until the next call to NewFrame()
5102{
5103 ImGuiContext& g = *GImGui;
5104 ImGuiViewportP* viewport = g.Viewports[0];
5105 return viewport->DrawDataP.Valid ? &viewport->DrawDataP : NULL;
5106}
5107
5109{
5110 return GImGui->Time;
5111}
5112
5114{
5115 return GImGui->FrameCount;
5116}
5117
5118static ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name)
5119{
5120 // Create the draw list on demand, because they are not frequently used for all viewports
5121 ImGuiContext& g = *GImGui;
5122 IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->BgFgDrawLists));
5123 ImDrawList* draw_list = viewport->BgFgDrawLists[drawlist_no];
5124 if (draw_list == NULL)
5125 {
5126 draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData);
5127 draw_list->_OwnerName = drawlist_name;
5128 viewport->BgFgDrawLists[drawlist_no] = draw_list;
5129 }
5130
5131 // Our ImDrawList system requires that there is always a command
5132 if (viewport->BgFgDrawListsLastFrame[drawlist_no] != g.FrameCount)
5133 {
5134 draw_list->_ResetForNewFrame();
5135 draw_list->PushTexture(g.IO.Fonts->TexRef);
5136 draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false);
5137 viewport->BgFgDrawListsLastFrame[drawlist_no] = g.FrameCount;
5138 }
5139 return draw_list;
5140}
5141
5143{
5144 if (viewport == NULL)
5145 viewport = GImGui->CurrentWindow->Viewport;
5146 return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 0, "##Background");
5147}
5148
5150{
5151 if (viewport == NULL)
5152 viewport = GImGui->CurrentWindow->Viewport;
5153 return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 1, "##Foreground");
5154}
5155
5157{
5158 return &GImGui->DrawListSharedData;
5159}
5160
5162{
5163 // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
5164 // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward.
5165 // This is because we want ActiveId to be set even when the window is not permitted to move.
5166 ImGuiContext& g = *GImGui;
5167 FocusWindow(window);
5168 SetActiveID(window->MoveId, window);
5170 g.NavCursorVisible = false;
5174
5175 bool can_move_window = true;
5177 can_move_window = false;
5178 if (ImGuiDockNode* node = window->DockNodeAsHost)
5179 if (node->VisibleWindow && (node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove))
5180 can_move_window = false;
5181 if (can_move_window)
5182 g.MovingWindow = window;
5183}
5184
5185// We use 'undock == false' when dragging from title bar to allow moving groups of floating nodes without undocking them.
5187{
5188 ImGuiContext& g = *GImGui;
5189 bool can_undock_node = false;
5190 if (undock && node != NULL && node->VisibleWindow && (node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove) == 0 && (node->MergedFlags & ImGuiDockNodeFlags_NoUndocking) == 0)
5191 {
5192 // Can undock if:
5193 // - part of a hierarchy with more than one visible node (if only one is visible, we'll just move the root window)
5194 // - part of a dockspace node hierarchy: so we can undock the last single visible node too. Undocking from a fixed/central node will create a new node and copy windows.
5195 ImGuiDockNode* root_node = DockNodeGetRootNode(node);
5196 if (root_node->OnlyNodeWithWindows != node || root_node->CentralNode != NULL) // -V1051 PVS-Studio thinks node should be root_node and is wrong about that.
5197 can_undock_node = true;
5198 }
5199
5200 const bool clicked = IsMouseClicked(0);
5201 const bool dragging = IsMouseDragging(0);
5202 if (can_undock_node && dragging)
5203 DockContextQueueUndockNode(&g, node); // Will lead to DockNodeStartMouseMovingWindow() -> StartMouseMovingWindow() being called next frame
5204 else if (!can_undock_node && (clicked || dragging) && g.MovingWindow != window)
5205 StartMouseMovingWindow(window);
5206}
5207
5208// Handle mouse moving window
5209// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()
5210// FIXME: We don't have strong guarantee that g.MovingWindow stay synced with g.ActiveId == g.MovingWindow->MoveId.
5211// This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs,
5212// but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other.
5214{
5215 ImGuiContext& g = *GImGui;
5216 if (g.MovingWindow != NULL)
5217 {
5218 // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).
5219 // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.
5222 ImGuiWindow* moving_window = g.MovingWindow->RootWindowDockTree;
5223
5224 // When a window stop being submitted while being dragged, it may will its viewport until next Begin()
5225 const bool window_disappared = (!moving_window->WasActive && !moving_window->Active);
5226 if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos) && !window_disappared)
5227 {
5229 if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
5230 {
5231 SetWindowPos(moving_window, pos, ImGuiCond_Always);
5232 if (moving_window->Viewport && moving_window->ViewportOwned) // Synchronize viewport immediately because some overlays may relies on clipping rectangle before we Begin() into the window.
5233 {
5234 moving_window->Viewport->Pos = pos;
5235 moving_window->Viewport->UpdateWorkRect();
5236 }
5237 }
5239 }
5240 else
5241 {
5242 if (!window_disappared)
5243 {
5244 // Try to merge the window back into the main viewport.
5245 // This works because MouseViewport should be != MovingWindow->Viewport on release (as per code in UpdateViewports)
5248
5249 // Restore the mouse viewport so that we don't hover the viewport _under_ the moved window during the frame we released the mouse button.
5250 if (moving_window->Viewport && !IsDragDropPayloadBeingAccepted())
5251 g.MouseViewport = moving_window->Viewport;
5252
5253 // Clear the NoInput window flag set by the Viewport system
5254 if (moving_window->Viewport)
5255 moving_window->Viewport->Flags &= ~ImGuiViewportFlags_NoInputs;
5256 }
5257
5258 g.MovingWindow = NULL;
5259 ClearActiveID();
5260 }
5261 }
5262 else
5263 {
5264 // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.
5266 {
5268 if (!g.IO.MouseDown[0])
5269 ClearActiveID();
5270 }
5271 }
5272}
5273
5274// Initiate focusing and moving window when clicking on empty space or title bar.
5275// Initiate focusing window when clicking on a disabled item.
5276// Handle left-click and right-click focus.
5278{
5279 ImGuiContext& g = *GImGui;
5280 if (g.ActiveId != 0 || (g.HoveredId != 0 && !g.HoveredIdIsDisabled))
5281 return;
5282
5283 // Unless we just made a window/popup appear
5284 if (g.NavWindow && g.NavWindow->Appearing)
5285 return;
5286
5287 // Click on empty space to focus window and start moving
5288 // (after we're done with all our widgets, so e.g. clicking on docking tab-bar which have set HoveredId already and not get us here!)
5289 if (g.IO.MouseClicked[0])
5290 {
5291 // Handle the edge case of a popup being closed while clicking in its empty space.
5292 // If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more.
5293 ImGuiWindow* root_window = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
5294 const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel);
5295
5296 if (root_window != NULL && !is_closed_popup)
5297 {
5299
5300 // Cancel moving if clicked outside of title bar
5302 if (!(root_window->Flags & ImGuiWindowFlags_NoTitleBar) || root_window->DockIsActive)
5303 if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
5304 g.MovingWindow = NULL;
5305
5306 // Cancel moving if clicked over an item which was disabled or inhibited by popups
5307 // (when g.HoveredIdIsDisabled == true && g.HoveredId == 0 we are inhibited by popups, when g.HoveredIdIsDisabled == true && g.HoveredId != 0 we are over a disabled item)0 already)
5308 if (g.HoveredIdIsDisabled)
5309 g.MovingWindow = NULL;
5310 }
5311 else if (root_window == NULL && g.NavWindow != NULL)
5312 {
5313 // Clicking on void disable focus
5315 }
5316 }
5317
5318 // With right mouse button we close popups without changing focus based on where the mouse is aimed
5319 // Instead, focus will be restored to the window under the bottom-most closed popup.
5320 // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger)
5321 if (g.IO.MouseClicked[1] && g.HoveredId == 0)
5322 {
5323 // Find the top-most window between HoveredWindow and the top-most Modal Window.
5324 // This is where we can trim the popup stack.
5326 bool hovered_window_above_modal = g.HoveredWindow && (modal == NULL || IsWindowAbove(g.HoveredWindow, modal));
5327 ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true);
5328 }
5329}
5330
5331// This is called during NewFrame()->UpdateViewportsNewFrame() only.
5332// Need to keep in sync with SetWindowPos()
5333static void TranslateWindow(ImGuiWindow* window, const ImVec2& delta)
5334{
5335 window->Pos += delta;
5336 window->ClipRect.Translate(delta);
5337 window->OuterRectClipped.Translate(delta);
5338 window->InnerRect.Translate(delta);
5339 window->DC.CursorPos += delta;
5340 window->DC.CursorStartPos += delta;
5341 window->DC.CursorMaxPos += delta;
5342 window->DC.IdealMaxPos += delta;
5343}
5344
5345static void ScaleWindow(ImGuiWindow* window, float scale)
5346{
5347 ImVec2 origin = window->Viewport->Pos;
5348 window->Pos = ImFloor((window->Pos - origin) * scale + origin);
5349 window->Size = ImTrunc(window->Size * scale);
5350 window->SizeFull = ImTrunc(window->SizeFull * scale);
5351 window->ContentSize = ImTrunc(window->ContentSize * scale);
5352}
5353
5355{
5356 return (window->Active) && (!window->Hidden);
5357}
5358
5359// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app)
5361{
5362 ImGuiContext& g = *GImGui;
5363 ImGuiIO& io = g.IO;
5364
5365 // FIXME-DPI: This storage was added on 2021/03/31 for test engine, but if we want to multiply WINDOWS_HOVER_PADDING
5366 // by DpiScale, we need to make this window-agnostic anyhow, maybe need storing inside ImGuiWindow.
5368
5369 // Find the window hovered by mouse:
5370 // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
5371 // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame.
5372 // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms.
5373 bool clear_hovered_windows = false;
5377
5378 // Modal windows prevents mouse from hovering behind them.
5379 ImGuiWindow* modal_window = GetTopMostPopupModal();
5380 if (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window)) // FIXME-MERGE: RootWindowDockTree ?
5381 clear_hovered_windows = true;
5382
5383 // Disabled mouse hovering (we don't currently clear MousePos, we could)
5385 clear_hovered_windows = true;
5386
5387 // We track click ownership. When clicked outside of a window the click is owned by the application and
5388 // won't report hovering nor request capture even while dragging over our windows afterward.
5389 const bool has_open_popup = (g.OpenPopupStack.Size > 0);
5390 const bool has_open_modal = (modal_window != NULL);
5391 int mouse_earliest_down = -1;
5392 bool mouse_any_down = false;
5393 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
5394 {
5395 if (io.MouseClicked[i])
5396 {
5397 io.MouseDownOwned[i] = (g.HoveredWindow != NULL) || has_open_popup;
5398 io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal;
5399 }
5400 mouse_any_down |= io.MouseDown[i];
5401 if (io.MouseDown[i] || io.MouseReleased[i]) // Increase release frame for our evaluation of earliest button (#1392)
5402 if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down])
5403 mouse_earliest_down = i;
5404 }
5405 const bool mouse_avail = (mouse_earliest_down == -1) || io.MouseDownOwned[mouse_earliest_down];
5406 const bool mouse_avail_unless_popup_close = (mouse_earliest_down == -1) || io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down];
5407
5408 // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
5409 // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
5410 const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
5411 if (!mouse_avail && !mouse_dragging_extern_payload)
5412 clear_hovered_windows = true;
5413
5414 if (clear_hovered_windows)
5416
5417 // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to Dear ImGui only, false = dispatch mouse to Dear ImGui + underlying app)
5418 // Update io.WantCaptureMouseAllowPopupClose (experimental) to give a chance for app to react to popup closure with a drag
5419 if (g.WantCaptureMouseNextFrame != -1)
5420 {
5422 }
5423 else
5424 {
5425 io.WantCaptureMouse = (mouse_avail && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_popup;
5426 io.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_modal;
5427 }
5428
5429 // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app)
5430 io.WantCaptureKeyboard = false;
5432 {
5433 if ((g.ActiveId != 0) || (modal_window != NULL))
5434 io.WantCaptureKeyboard = true;
5436 io.WantCaptureKeyboard = true;
5437 }
5438 if (g.WantCaptureKeyboardNextFrame != -1) // Manual override
5440
5441 // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
5442 io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
5443}
5444
5446{
5447 // Cannot update every atlases based on atlas's FrameCount < g.FrameCount, because an atlas may be shared by multiple contexts with different frame count.
5448 ImGuiContext& g = *GImGui;
5449 const bool has_textures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0;
5450 for (ImFontAtlas* atlas : g.FontAtlases)
5451 {
5452 if (atlas->OwnerContext == &g)
5453 {
5454 ImFontAtlasUpdateNewFrame(atlas, g.FrameCount, has_textures);
5455 }
5456 else
5457 {
5458 // (1) If you manage font atlases yourself, e.g. create a ImFontAtlas yourself you need to call ImFontAtlasUpdateNewFrame() on it.
5459 // Otherwise, calling ImGui::CreateContext() without parameter will create an atlas owned by the context.
5460 // (2) If you have multiple font atlases, make sure the 'atlas->RendererHasTextures' as specified in the ImFontAtlasUpdateNewFrame() call matches for that.
5461 // (3) If you have multiple imgui contexts, they also need to have a matching value for ImGuiBackendFlags_RendererHasTextures.
5462 IM_ASSERT(atlas->Builder != NULL && atlas->Builder->FrameCount != -1);
5463 IM_ASSERT(atlas->RendererHasTextures == has_textures);
5464 }
5465 }
5466}
5467
5468// Build a single texture list
5470{
5471 ImGuiContext& g = *GImGui;
5473 for (ImFontAtlas* atlas : g.FontAtlases)
5474 for (ImTextureData* tex : atlas->TexList)
5475 {
5476 // We provide this information so backends can decide whether to destroy textures.
5477 // This means in practice that if N imgui contexts are created with a shared atlas, we assume all of them have a backend initialized.
5478 tex->RefCount = (unsigned short)atlas->RefCount;
5480 }
5481 for (ImTextureData* tex : g.UserTextures)
5483}
5484
5485// Called once a frame. Followed by SetCurrentFont() which sets up the remaining data.
5486// FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal!
5488{
5489 ImGuiContext& g = *GImGui;
5490 ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
5491 for (ImGuiViewportP* viewport : g.Viewports)
5492 virtual_space.Add(viewport->GetMainRect());
5493 g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4();
5497 if (g.Style.AntiAliasedLines)
5501 if (g.Style.AntiAliasedFill)
5505 g.DrawListSharedData.InitialFringeScale = 1.0f; // FIXME-DPI: Change this for some DPI scaling experiments.
5506}
5507
5509{
5510 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
5511 ImGuiContext& g = *GImGui;
5512
5513 // Remove pending delete hooks before frame start.
5514 // This deferred removal avoid issues of removal while iterating the hook vector
5515 for (int n = g.Hooks.Size - 1; n >= 0; n--)
5517 g.Hooks.erase(&g.Hooks[n]);
5518
5520
5521 // Check and assert for various common IO and Configuration mistakes
5525
5526 // Load settings on first frame, save settings when modified (after a delay)
5528
5529 g.Time += g.IO.DeltaTime;
5530 g.FrameCount += 1;
5532 g.WindowsActiveCount = 0;
5534
5535 // Calculate frame-rate for the user, as a purely luxurious feature
5540 g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX;
5541
5542 // Process input queue (trickle as many events as possible), turn events into writes to IO structure
5545
5546 // Update viewports (after processing input queue, so io.MouseHoveredViewport is set)
5548
5549 // Update texture list (collect destroyed textures, etc.)
5551
5552 // Setup current font and draw list shared data
5555
5556 g.WithinFrameScope = true;
5557
5558 // Mark rendering data as invalid to prevent user who may have a handle on it to use it.
5559 for (ImGuiViewportP* viewport : g.Viewports)
5560 {
5561 viewport->DrawData = NULL;
5562 viewport->DrawDataP.Valid = false;
5563 }
5564
5565 // Drag and drop keep the source ID alive so even if the source disappear our state is consistent
5568
5569 // [DEBUG]
5570 if (!g.IO.ConfigDebugHighlightIdConflicts || !g.IO.KeyCtrl) // Count is locked while holding CTRL
5574
5575 // Update HoveredId data
5577 g.HoveredIdTimer = 0.0f;
5578 if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId))
5579 g.HoveredIdNotActiveTimer = 0.0f;
5580 if (g.HoveredId)
5582 if (g.HoveredId && g.ActiveId != g.HoveredId)
5586 g.HoveredId = 0;
5587 g.HoveredIdAllowOverlap = false;
5588 g.HoveredIdIsDisabled = false;
5589
5590 // Clear ActiveID if the item is not alive anymore.
5591 // In 1.87, the common most call to KeepAliveID() was moved from GetID() to ItemAdd().
5592 // As a result, custom widget using ButtonBehavior() _without_ ItemAdd() need to call KeepAliveID() themselves.
5593 if (g.ActiveId != 0 && g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId)
5594 {
5595 IMGUI_DEBUG_LOG_ACTIVEID("NewFrame(): ClearActiveID() because it isn't marked alive anymore!\n");
5596 ClearActiveID();
5597 }
5598
5599 // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)
5600 if (g.ActiveId)
5601 g.ActiveIdTimer += g.IO.DeltaTime;
5604 g.ActiveIdIsAlive = 0;
5606 g.ActiveIdIsJustActivated = false;
5607 if (g.TempInputId != 0 && g.ActiveId != g.TempInputId)
5608 g.TempInputId = 0;
5609 if (g.ActiveId == 0)
5610 {
5611 g.ActiveIdUsingNavDirMask = 0x00;
5613 }
5615 g.DeactivatedItemData.ID = 0;
5616 g.DeactivatedItemData.IsAlive = false;
5617
5618 // Record when we have been stationary as this state is preserved while over same item.
5619 // FIXME: The way this is expressed means user cannot alter HoverStationaryDelay during the frame to use varying values.
5620 // To allow this we should store HoverItemMaxStationaryTime+ID and perform the >= check in IsItemHovered() function.
5623 else if (g.HoverItemDelayId == 0)
5627 else if (g.HoveredWindow == NULL)
5629
5630 // Update hover delay for IsItemHovered() with delays and tooltips
5632 if (g.HoverItemDelayId != 0)
5633 {
5635 g.HoverItemDelayClearTimer = 0.0f;
5636 g.HoverItemDelayId = 0;
5637 }
5638 else if (g.HoverItemDelayTimer > 0.0f)
5639 {
5640 // This gives a little bit of leeway before clearing the hover timer, allowing mouse to cross gaps
5641 // We could expose 0.25f as style.HoverClearDelay but I am not sure of the logic yet, this is particularly subtle.
5643 if (g.HoverItemDelayClearTimer >= ImMax(0.25f, g.IO.DeltaTime * 2.0f)) // ~7 frames at 30 Hz + allow for low framerate
5644 g.HoverItemDelayTimer = g.HoverItemDelayClearTimer = 0.0f; // May want a decaying timer, in which case need to clamp at max first, based on max of caller last requested timer.
5645 }
5646
5647 // Drag and drop
5651 g.DragDropWithinSource = false;
5652 g.DragDropWithinTarget = false;
5654 g.TooltipPreviousWindow = NULL;
5655
5656 // Close popups on focus lost (currently wip/opt-in)
5657 //if (g.IO.AppFocusLost)
5658 // ClosePopupsExceptModals();
5659
5660 // Update keyboard input state
5662
5663 //IM_ASSERT(g.IO.KeyCtrl == IsKeyDown(ImGuiKey_LeftCtrl) || IsKeyDown(ImGuiKey_RightCtrl));
5664 //IM_ASSERT(g.IO.KeyShift == IsKeyDown(ImGuiKey_LeftShift) || IsKeyDown(ImGuiKey_RightShift));
5665 //IM_ASSERT(g.IO.KeyAlt == IsKeyDown(ImGuiKey_LeftAlt) || IsKeyDown(ImGuiKey_RightAlt));
5666 //IM_ASSERT(g.IO.KeySuper == IsKeyDown(ImGuiKey_LeftSuper) || IsKeyDown(ImGuiKey_RightSuper));
5667
5668 // Update keyboard/gamepad navigation
5669 NavUpdate();
5670
5671 // Update mouse input state
5673
5674 // Undocking
5675 // (needs to be before UpdateMouseMovingWindowNewFrame so the window is already offset and following the mouse on the detaching frame)
5677
5678 // Mark all windows as not visible and compact unused memory.
5680 const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
5681 for (ImGuiWindow* window : g.Windows)
5682 {
5683 window->WasActive = window->Active;
5684 window->Active = false;
5685 window->WriteAccessed = false;
5686 window->BeginCountPreviousFrame = window->BeginCount;
5687 window->BeginCount = 0;
5688
5689 // Garbage collect transient buffers of recently unused windows
5690 if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
5692 }
5693
5694 // Find hovered window
5695 // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
5696 // (currently needs to be done after the WasActive=Active loop and FindHoveredWindowEx uses ->Active)
5698
5699 // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
5701
5702 // Background darkening/whitening
5703 if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
5704 g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
5705 else
5706 g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
5707
5710
5711 // Platform IME data: reset for the frame
5714
5715 // Mouse wheel scrolling, scale
5717
5718 // Garbage collect transient buffers of recently unused tables
5719 for (int i = 0; i < g.TablesLastTimeActive.Size; i++)
5720 if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)
5722 for (ImGuiTableTempData& table_temp_data : g.TablesTempData)
5723 if (table_temp_data.LastTimeActive >= 0.0f && table_temp_data.LastTimeActive < memory_compact_start_time)
5724 TableGcCompactTransientBuffers(&table_temp_data);
5725 if (g.GcCompactAll)
5727 g.GcCompactAll = false;
5728
5729 // Closing the focused window restore focus to the first active root window in descending z-order
5730 if (g.NavWindow && !g.NavWindow->WasActive)
5732
5733 // No window should be open at the beginning of the frame.
5734 // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
5740 g.GroupStack.resize(0);
5741
5742 // Docking
5744
5745 // [DEBUG] Update debug features
5746#ifndef IMGUI_DISABLE_DEBUG_TOOLS
5750 if (g.DebugLocateFrames > 0 && --g.DebugLocateFrames == 0)
5751 {
5752 g.DebugLocateId = 0;
5753 g.DebugBreakInLocateId = false;
5754 }
5756 {
5757 DebugLog("(Debug Log: Auto-disabled some ImGuiDebugLogFlags after 2 frames)\n");
5758 g.DebugLogFlags &= ~g.DebugLogAutoDisableFlags;
5760 }
5761#endif
5762
5763 // Create implicit/fallback window - which we will only render it if the user has added something to it.
5764 // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
5765 // This fallback is particularly important as it prevents ImGui:: calls from crashing.
5768 Begin("Debug##Default");
5770
5771 // Store stack sizes
5774
5775 // [DEBUG] When io.ConfigDebugBeginReturnValue is set, we make Begin()/BeginChild() return false at different level of the window-stack,
5776 // allowing to validate correct Begin/End behavior in user code.
5777#ifndef IMGUI_DISABLE_DEBUG_TOOLS
5780 else
5782#endif
5783
5785}
5786
5787// FIXME: Add a more explicit sort order in the window structure.
5788static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
5789{
5790 const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;
5791 const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;
5792 if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
5793 return d;
5795 return d;
5797}
5798
5799static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
5800{
5801 out_sorted_windows->push_back(window);
5802 if (window->Active)
5803 {
5804 int count = window->DC.ChildWindows.Size;
5805 ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
5806 for (int i = 0; i < count; i++)
5807 {
5808 ImGuiWindow* child = window->DC.ChildWindows[i];
5809 if (child->Active)
5810 AddWindowToSortBuffer(out_sorted_windows, child);
5811 }
5812 }
5813}
5814
5815static void AddWindowToDrawData(ImGuiWindow* window, int layer)
5816{
5817 ImGuiContext& g = *GImGui;
5818 ImGuiViewportP* viewport = window->Viewport;
5819 IM_ASSERT(viewport != NULL);
5821 if (window->DrawList->_Splitter._Count > 1)
5822 window->DrawList->ChannelsMerge(); // Merge if user forgot to merge back. Also required in Docking branch for ImGuiWindowFlags_DockNodeHost windows.
5823 ImGui::AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[layer], window->DrawList);
5824 for (ImGuiWindow* child : window->DC.ChildWindows)
5825 if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active
5826 AddWindowToDrawData(child, layer);
5827}
5828
5829static inline int GetWindowDisplayLayer(ImGuiWindow* window)
5830{
5831 return (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0;
5832}
5833
5834// Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu)
5835static inline void AddRootWindowToDrawData(ImGuiWindow* window)
5836{
5838}
5839
5841{
5842 int n = builder->Layers[0]->Size;
5843 int full_size = n;
5844 for (int i = 1; i < IM_ARRAYSIZE(builder->Layers); i++)
5845 full_size += builder->Layers[i]->Size;
5846 builder->Layers[0]->resize(full_size);
5847 for (int layer_n = 1; layer_n < IM_ARRAYSIZE(builder->Layers); layer_n++)
5848 {
5849 ImVector<ImDrawList*>* layer = builder->Layers[layer_n];
5850 if (layer->empty())
5851 continue;
5852 memcpy(builder->Layers[0]->Data + n, layer->Data, layer->Size * sizeof(ImDrawList*));
5853 n += layer->Size;
5854 layer->resize(0);
5855 }
5856}
5857
5859{
5860 ImGuiIO& io = ImGui::GetIO();
5861 ImDrawData* draw_data = &viewport->DrawDataP;
5862
5863 viewport->DrawData = draw_data; // Make publicly accessible
5864 viewport->DrawDataBuilder.Layers[0] = &draw_data->CmdLists;
5865 viewport->DrawDataBuilder.Layers[1] = &viewport->DrawDataBuilder.LayerData1;
5866 viewport->DrawDataBuilder.Layers[0]->resize(0);
5867 viewport->DrawDataBuilder.Layers[1]->resize(0);
5868
5869 // When minimized, we report draw_data->DisplaySize as zero to be consistent with non-viewport mode,
5870 // and to allow applications/backends to easily skip rendering.
5871 // FIXME: Note that we however do NOT attempt to report "zero drawlist / vertices" into the ImDrawData structure.
5872 // This is because the work has been done already, and its wasted! We should fix that and add optimizations for
5873 // it earlier in the pipeline, rather than pretend to hide the data at the end of the pipeline.
5874 const bool is_minimized = (viewport->Flags & ImGuiViewportFlags_IsMinimized) != 0;
5875
5876 draw_data->Valid = true;
5877 draw_data->CmdListsCount = 0;
5878 draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;
5879 draw_data->DisplayPos = viewport->Pos;
5880 draw_data->DisplaySize = is_minimized ? ImVec2(0.0f, 0.0f) : viewport->Size;
5881 draw_data->FramebufferScale = (viewport->FramebufferScale.x != 0.0f) ? viewport->FramebufferScale : io.DisplayFramebufferScale;
5882 draw_data->OwnerViewport = viewport;
5883 draw_data->Textures = &ImGui::GetPlatformIO().Textures;
5884}
5885
5886// Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering.
5887// - When using this function it is sane to ensure that float are perfectly rounded to integer values,
5888// so that e.g. (int)(max.x-min.x) in user's render produce correct result.
5889// - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect():
5890// some frequently called functions which to modify both channels and clipping simultaneously tend to use the
5891// more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds.
5892// - This is analogous to PushFont()/PopFont() in the sense that are a mixing a global stack and a window stack,
5893// which in the case of ClipRect is not so problematic but tends to be more restrictive for fonts.
5894void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
5895{
5896 ImGuiWindow* window = GetCurrentWindow();
5897 window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
5898 window->ClipRect = window->DrawList->_ClipRectStack.back();
5899}
5900
5902{
5903 ImGuiWindow* window = GetCurrentWindow();
5904 window->DrawList->PopClipRect();
5905 window->ClipRect = window->DrawList->_ClipRectStack.back();
5906}
5907
5909{
5910 for (int n = window->DC.ChildWindows.Size - 1; n >= 0; n--)
5913 return window;
5914}
5915
5917{
5918 if ((col & IM_COL32_A_MASK) == 0)
5919 return;
5920
5921 ImGuiViewportP* viewport = window->Viewport;
5922 ImRect viewport_rect = viewport->GetMainRect();
5923
5924 // Draw behind window by moving the draw command at the FRONT of the draw list
5925 {
5926 // Draw list have been trimmed already, hence the explicit recreation of a draw command if missing.
5927 // FIXME: This is creating complication, might be simpler if we could inject a drawlist in drawdata at a given position and not attempt to manipulate ImDrawCmd order.
5928 ImDrawList* draw_list = window->RootWindowDockTree->DrawList;
5929 draw_list->ChannelsMerge();
5930 if (draw_list->CmdBuffer.Size == 0)
5931 draw_list->AddDrawCmd();
5932 draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that)
5933 draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col);
5934 ImDrawCmd cmd = draw_list->CmdBuffer.back();
5935 IM_ASSERT(cmd.ElemCount == 6);
5936 draw_list->CmdBuffer.pop_back();
5937 draw_list->CmdBuffer.push_front(cmd);
5938 draw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.back().IdxOffset won't be correct if we append to same command.
5939 draw_list->PopClipRect();
5940 }
5941
5942 // Draw over sibling docking nodes in a same docking tree
5943 if (window->RootWindow->DockIsActive)
5944 {
5946 draw_list->ChannelsMerge();
5947 if (draw_list->CmdBuffer.Size == 0)
5948 draw_list->AddDrawCmd();
5949 draw_list->PushClipRect(viewport_rect.Min, viewport_rect.Max, false);
5950 RenderRectFilledWithHole(draw_list, window->RootWindowDockTree->Rect(), window->RootWindow->Rect(), col, 0.0f);// window->RootWindowDockTree->WindowRounding);
5951 draw_list->PopClipRect();
5952 }
5953}
5954
5956{
5957 ImGuiContext& g = *GImGui;
5958 ImGuiWindow* bottom_most_visible_window = parent_window;
5959 for (int i = FindWindowDisplayIndex(parent_window); i >= 0; i--)
5960 {
5961 ImGuiWindow* window = g.Windows[i];
5962 if (window->Flags & ImGuiWindowFlags_ChildWindow)
5963 continue;
5964 if (!IsWindowWithinBeginStackOf(window, parent_window))
5965 break;
5966 if (IsWindowActiveAndVisible(window) && GetWindowDisplayLayer(window) <= GetWindowDisplayLayer(parent_window))
5967 bottom_most_visible_window = window;
5968 }
5969 return bottom_most_visible_window;
5970}
5971
5972// Important: AddWindowToDrawData() has not been called yet, meaning DockNodeHost windows needs a DrawList->ChannelsMerge() before usage.
5973// We call ChannelsMerge() lazily here at it is faster that doing a full iteration of g.Windows[] prior to calling RenderDimmedBackgrounds().
5975{
5976 ImGuiContext& g = *GImGui;
5978 if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
5979 return;
5980 const bool dim_bg_for_modal = (modal_window != NULL);
5981 const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.NavWindowingTargetAnim->Active);
5982 if (!dim_bg_for_modal && !dim_bg_for_window_list)
5983 return;
5984
5985 ImGuiViewport* viewports_already_dimmed[2] = { NULL, NULL };
5986 if (dim_bg_for_modal)
5987 {
5988 // Draw dimming behind modal or a begin stack child, whichever comes first in draw order.
5989 ImGuiWindow* dim_behind_window = FindBottomMostVisibleWindowWithinBeginStack(modal_window);
5990 RenderDimmedBackgroundBehindWindow(dim_behind_window, GetColorU32(modal_window->DC.ModalDimBgColor, g.DimBgRatio));
5991 viewports_already_dimmed[0] = modal_window->Viewport;
5992 }
5993 else if (dim_bg_for_window_list)
5994 {
5995 // Draw dimming behind CTRL+Tab target window and behind CTRL+Tab UI window
5999 viewports_already_dimmed[0] = g.NavWindowingTargetAnim->Viewport;
6000 viewports_already_dimmed[1] = g.NavWindowingListWindow ? g.NavWindowingListWindow->Viewport : NULL;
6001
6002 // Draw border around CTRL+Tab target window
6004 ImGuiViewport* viewport = window->Viewport;
6005 float distance = g.FontSize;
6006 ImRect bb = window->Rect();
6007 bb.Expand(distance);
6008 if (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y)
6009 bb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward
6010 window->DrawList->ChannelsMerge();
6011 if (window->DrawList->CmdBuffer.Size == 0)
6012 window->DrawList->AddDrawCmd();
6013 window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size);
6015 window->DrawList->PopClipRect();
6016 }
6017
6018 // Draw dimming background on _other_ viewports than the ones our windows are in
6019 for (ImGuiViewportP* viewport : g.Viewports)
6020 {
6021 if (viewport == viewports_already_dimmed[0] || viewport == viewports_already_dimmed[1])
6022 continue;
6023 if (modal_window && viewport->Window && IsWindowAbove(viewport->Window, modal_window))
6024 continue;
6025 ImDrawList* draw_list = GetForegroundDrawList(viewport);
6026 const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio);
6027 draw_list->AddRectFilled(viewport->Pos, viewport->Pos + viewport->Size, dim_bg_col);
6028 }
6029}
6030
6031// This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal.
6033{
6034 ImGuiContext& g = *GImGui;
6036
6037 // Don't process EndFrame() multiple times.
6038 if (g.FrameCountEnded == g.FrameCount)
6039 return;
6040 if (!g.WithinFrameScope)
6041 {
6042 IM_ASSERT_USER_ERROR(g.WithinFrameScope, "Forgot to call ImGui::NewFrame()?");
6043 return;
6044 }
6045
6047
6048 // [EXPERIMENTAL] Recover from errors
6049 if (g.IO.ConfigErrorRecovery)
6053
6054 // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
6056 if (g.PlatformIO.Platform_SetImeDataFn != NULL && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0)
6057 {
6058 ImGuiViewport* viewport = FindViewportByID(ime_data->ViewportId);
6059 IMGUI_DEBUG_LOG_IO("[io] Calling Platform_SetImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y);
6060 if (viewport == NULL)
6061 viewport = GetMainViewport();
6062 g.PlatformIO.Platform_SetImeDataFn(&g, viewport, ime_data);
6063 }
6064 g.WantTextInputNextFrame = ime_data->WantTextInput ? 1 : 0;
6065
6066 // Hide implicit/fallback "Debug" window if it hasn't been used
6069 g.CurrentWindow->Active = false;
6070 End();
6071
6072 // Update navigation: CTRL+Tab, wrap-around requests
6073 NavEndFrame();
6074
6075 // Update docking
6077
6078 SetCurrentViewport(NULL, NULL);
6079
6080 // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted)
6081 if (g.DragDropActive)
6082 {
6083 bool is_delivered = g.DragDropPayload.Delivery;
6085 if (is_delivered || is_elapsed)
6086 ClearDragDrop();
6087 }
6088
6089 // Drag and Drop: Fallback for missing source tooltip. This is not ideal but better than nothing.
6090 // If you want to handle source item disappearing: instead of submitting your description tooltip
6091 // in the BeginDragDropSource() block of the dragged item, you can submit them from a safe single spot
6092 // (e.g. end of your item loop, or before EndFrame) by reading payload data.
6093 // In the typical case, the contents of drag tooltip should be possible to infer solely from payload data.
6095 {
6096 g.DragDropWithinSource = true;
6097 SetTooltip("...");
6098 g.DragDropWithinSource = false;
6099 }
6100
6101 // End frame
6102 g.WithinFrameScope = false;
6105
6106 // Initiate moving window + handle left-click and right-click focus
6108
6109 // Update user-facing viewport list (g.Viewports -> g.PlatformIO.Viewports after filtering out some)
6111
6112 // Sort the window list so that all child windows are after their parent
6113 // We cannot do that on FocusWindow() because children may not exist yet
6116 for (ImGuiWindow* window : g.Windows)
6117 {
6118 if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it
6119 continue;
6121 }
6122
6123 // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong.
6127
6129
6130 // Unlock font atlas
6131 for (ImFontAtlas* atlas : g.FontAtlases)
6132 atlas->Locked = false;
6133
6134 // Clear Input data for next frame
6135 g.IO.MousePosPrev = g.IO.MousePos;
6136 g.IO.AppFocusLost = false;
6137 g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
6139
6141}
6142
6143// Prepare the data for rendering so you can call GetDrawData()
6144// (As with anything within the ImGui:: namespace this doesn't touch your GPU or graphics API at all:
6145// it is the role of the ImGui_ImplXXXX_RenderDrawData() function provided by the renderer backend)
6147{
6148 ImGuiContext& g = *GImGui;
6150
6151 if (g.FrameCountEnded != g.FrameCount)
6152 EndFrame();
6153 if (g.FrameCountRendered == g.FrameCount)
6154 return;
6156
6159
6160 // Add background ImDrawList (for each active viewport)
6161 for (ImGuiViewportP* viewport : g.Viewports)
6162 {
6163 InitViewportDrawData(viewport);
6164 if (viewport->BgFgDrawLists[0] != NULL)
6166 }
6167
6168 // Draw modal/window whitening backgrounds
6170
6171 // Add ImDrawList to render
6172 ImGuiWindow* windows_to_render_top_most[2];
6174 windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL);
6175 for (ImGuiWindow* window : g.Windows)
6176 {
6177 IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'"
6178 if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
6180 }
6181 for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++)
6182 if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window
6183 AddRootWindowToDrawData(windows_to_render_top_most[n]);
6184
6185 // Draw software mouse cursor if requested by io.MouseDrawCursor flag
6188
6189 // Setup ImDrawData structures for end-user
6191 for (ImGuiViewportP* viewport : g.Viewports)
6192 {
6194
6195 // Add foreground ImDrawList (for each active viewport)
6196 if (viewport->BgFgDrawLists[1] != NULL)
6198
6199 // We call _PopUnusedDrawCmd() last thing, as RenderDimmedBackgrounds() rely on a valid command being there (especially in docking branch).
6200 ImDrawData* draw_data = &viewport->DrawDataP;
6201 IM_ASSERT(draw_data->CmdLists.Size == draw_data->CmdListsCount);
6202 for (ImDrawList* draw_list : draw_data->CmdLists)
6203 draw_list->_PopUnusedDrawCmd();
6204
6205 g.IO.MetricsRenderVertices += draw_data->TotalVtxCount;
6206 g.IO.MetricsRenderIndices += draw_data->TotalIdxCount;
6207 }
6208
6209#ifndef IMGUI_DISABLE_DEBUG_TOOLS
6211 for (ImFontAtlas* atlas : g.FontAtlases)
6213#endif
6214
6216}
6217
6218// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
6219// CalcTextSize("") should return ImVec2(0.0f, g.FontSize)
6220ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
6221{
6222 ImGuiContext& g = *GImGui;
6223
6224 const char* text_display_end;
6225 if (hide_text_after_double_hash)
6226 text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string
6227 else
6228 text_display_end = text_end;
6229
6230 ImFont* font = g.Font;
6231 const float font_size = g.FontSize;
6232 if (text == text_display_end)
6233 return ImVec2(0.0f, font_size);
6234 ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
6235
6236 // Round
6237 // FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out.
6238 // FIXME: Investigate using ceilf or e.g.
6239 // - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c
6240 // - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html
6241 text_size.x = IM_TRUNC(text_size.x + 0.99999f);
6242
6243 return text_size;
6244}
6245
6246// Find window given position, search front-to-back
6247// - Typically write output back to g.HoveredWindow and g.HoveredWindowUnderMovingWindow.
6248// - FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically
6249// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is
6250// called, aka before the next Begin(). Moving window isn't affected.
6251// - The 'find_first_and_in_any_viewport = true' mode is only used by TestEngine. It is simpler to maintain here.
6252void ImGui::FindHoveredWindowEx(const ImVec2& pos, bool find_first_and_in_any_viewport, ImGuiWindow** out_hovered_window, ImGuiWindow** out_hovered_window_under_moving_window)
6253{
6254 ImGuiContext& g = *GImGui;
6255 ImGuiWindow* hovered_window = NULL;
6256 ImGuiWindow* hovered_window_under_moving_window = NULL;
6257
6258 // Special handling for the window being moved: Ignore the mouse viewport check (because it may reset/lose its viewport during the undocking frame)
6259 ImGuiViewportP* backup_moving_window_viewport = NULL;
6260 if (find_first_and_in_any_viewport == false && g.MovingWindow)
6261 {
6262 backup_moving_window_viewport = g.MovingWindow->Viewport;
6265 hovered_window = g.MovingWindow;
6266 }
6267
6268 ImVec2 padding_regular = g.Style.TouchExtraPadding;
6270 for (int i = g.Windows.Size - 1; i >= 0; i--)
6271 {
6272 ImGuiWindow* window = g.Windows[i];
6273 IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.
6274 if (!window->WasActive || window->Hidden)
6275 continue;
6277 continue;
6278 IM_ASSERT(window->Viewport);
6279 if (window->Viewport != g.MouseViewport)
6280 continue;
6281
6282 // Using the clipped AABB, a child window will typically be clipped by its parent (not always)
6283 ImVec2 hit_padding = (window->Flags & (ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) ? padding_regular : padding_for_resize;
6284 if (!window->OuterRectClipped.ContainsWithPad(pos, hit_padding))
6285 continue;
6286
6287 // Support for one rectangular hole in any given window
6288 // FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512)
6289 if (window->HitTestHoleSize.x != 0)
6290 {
6291 ImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y);
6292 ImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y);
6293 if (ImRect(hole_pos, hole_pos + hole_size).Contains(pos))
6294 continue;
6295 }
6296
6297 if (find_first_and_in_any_viewport)
6298 {
6299 hovered_window = window;
6300 break;
6301 }
6302 else
6303 {
6304 if (hovered_window == NULL)
6305 hovered_window = window;
6306 IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.
6307 if (hovered_window_under_moving_window == NULL && (!g.MovingWindow || window->RootWindowDockTree != g.MovingWindow->RootWindowDockTree))
6308 hovered_window_under_moving_window = window;
6309 if (hovered_window && hovered_window_under_moving_window)
6310 break;
6311 }
6312 }
6313
6314 *out_hovered_window = hovered_window;
6315 if (out_hovered_window_under_moving_window != NULL)
6316 *out_hovered_window_under_moving_window = hovered_window_under_moving_window;
6317 if (find_first_and_in_any_viewport == false && g.MovingWindow)
6318 g.MovingWindow->Viewport = backup_moving_window_viewport;
6319}
6320
6322{
6323 ImGuiContext& g = *GImGui;
6324 if (g.ActiveId)
6325 return g.ActiveId == g.LastItemData.ID;
6326 return false;
6327}
6328
6330{
6331 ImGuiContext& g = *GImGui;
6332 if (g.ActiveId)
6334 return true;
6335 return false;
6336}
6337
6339{
6340 ImGuiContext& g = *GImGui;
6344}
6345
6347{
6348 ImGuiContext& g = *GImGui;
6350}
6351
6352// == (GetItemID() == GetFocusID() && GetFocusID() != 0)
6354{
6355 ImGuiContext& g = *GImGui;
6356 if (g.NavId != g.LastItemData.ID || g.NavId == 0)
6357 return false;
6358
6359 // Special handling for the dummy item after Begin() which represent the title bar or tab.
6360 // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
6361 ImGuiWindow* window = g.CurrentWindow;
6362 if (g.LastItemData.ID == window->ID && window->WriteAccessed)
6363 return false;
6364
6365 return true;
6366}
6367
6368// Important: this can be useful but it is NOT equivalent to the behavior of e.g.Button()!
6369// Most widgets have specific reactions based on mouse-up/down state, mouse position etc.
6371{
6372 return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None);
6373}
6374
6376{
6377 ImGuiContext& g = *GImGui;
6378 return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
6379}
6380
6381// Call after a Selectable() or TreeNode() involved in multi-selection.
6382// Useful if you need the per-item information before reaching EndMultiSelect(), e.g. for rendering purpose.
6383// This is only meant to be called inside a BeginMultiSelect()/EndMultiSelect() block.
6384// (Outside of multi-select, it would be misleading/ambiguous to report this signal, as widgets
6385// return e.g. a pressed event and user code is in charge of altering selection in ways we cannot predict.)
6387{
6388 ImGuiContext& g = *GImGui;
6389 IM_ASSERT(g.CurrentMultiSelect != NULL); // Can only be used inside a BeginMultiSelect()/EndMultiSelect()
6391}
6392
6393// IMPORTANT: If you are trying to check whether your mouse should be dispatched to Dear ImGui or to your underlying app,
6394// you should not use this function! Use the 'io.WantCaptureMouse' boolean for that!
6395// Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" for details.
6397{
6398 ImGuiContext& g = *GImGui;
6399 return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
6400}
6401
6403{
6404 ImGuiContext& g = *GImGui;
6405 return g.ActiveId != 0;
6406}
6407
6409{
6410 ImGuiContext& g = *GImGui;
6411 return g.NavId != 0 && g.NavCursorVisible;
6412}
6413
6415{
6416 ImGuiContext& g = *GImGui;
6418}
6419
6421{
6422 ImGuiContext& g = *GImGui;
6424}
6425
6426// Allow next item to be overlapped by subsequent items.
6427// This works by requiring HoveredId to match for two subsequent frames,
6428// so if a following items overwrite it our interactions will naturally be disabled.
6430{
6431 ImGuiContext& g = *GImGui;
6433}
6434
6435#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
6436// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
6437// FIXME-LEGACY: Use SetNextItemAllowOverlap() *before* your item instead.
6439{
6440 ImGuiContext& g = *GImGui;
6441 ImGuiID id = g.LastItemData.ID;
6442 if (g.HoveredId == id)
6443 g.HoveredIdAllowOverlap = true;
6444 if (g.ActiveId == id) // Before we made this obsolete, most calls to SetItemAllowOverlap() used to avoid this path by testing g.ActiveId != id.
6445 g.ActiveIdAllowOverlap = true;
6446}
6447#endif
6448
6449// This is a shortcut for not taking ownership of 100+ keys, frequently used by drag operations.
6450// FIXME: It might be undesirable that this will likely disable KeyOwner-aware shortcuts systems. Consider a more fine-tuned version if needed?
6452{
6453 ImGuiContext& g = *GImGui;
6454 IM_ASSERT(g.ActiveId != 0);
6458}
6459
6461{
6462 ImGuiContext& g = *GImGui;
6463 return g.LastItemData.ID;
6464}
6465
6467{
6468 ImGuiContext& g = *GImGui;
6469 return g.LastItemData.Rect.Min;
6470}
6471
6473{
6474 ImGuiContext& g = *GImGui;
6475 return g.LastItemData.Rect.Max;
6476}
6477
6479{
6480 ImGuiContext& g = *GImGui;
6481 return g.LastItemData.Rect.GetSize();
6482}
6483
6484// Prior to v1.90 2023/10/16, the BeginChild() function took a 'bool border = false' parameter instead of 'ImGuiChildFlags child_flags = 0'.
6485// ImGuiChildFlags_Borders is defined as always == 1 in order to allow old code passing 'true'. Read comments in imgui.h for details!
6486bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags)
6487{
6488 ImGuiID id = GetCurrentWindow()->GetID(str_id);
6489 return BeginChildEx(str_id, id, size_arg, child_flags, window_flags);
6490}
6491
6492bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags)
6493{
6494 return BeginChildEx(NULL, id, size_arg, child_flags, window_flags);
6495}
6496
6497bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags)
6498{
6499 ImGuiContext& g = *GImGui;
6500 ImGuiWindow* parent_window = g.CurrentWindow;
6501 IM_ASSERT(id != 0);
6502
6503 // Sanity check as it is likely that some user will accidentally pass ImGuiWindowFlags into the ImGuiChildFlags argument.
6505 IM_UNUSED(ImGuiChildFlags_SupportedMask_);
6506 IM_ASSERT((child_flags & ~ImGuiChildFlags_SupportedMask_) == 0 && "Illegal ImGuiChildFlags value. Did you pass ImGuiWindowFlags values instead of ImGuiChildFlags?");
6507 IM_ASSERT((window_flags & ImGuiWindowFlags_AlwaysAutoResize) == 0 && "Cannot specify ImGuiWindowFlags_AlwaysAutoResize for BeginChild(). Use ImGuiChildFlags_AlwaysAutoResize!");
6508 if (child_flags & ImGuiChildFlags_AlwaysAutoResize)
6509 {
6510 IM_ASSERT((child_flags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY)) == 0 && "Cannot use ImGuiChildFlags_ResizeX or ImGuiChildFlags_ResizeY with ImGuiChildFlags_AlwaysAutoResize!");
6511 IM_ASSERT((child_flags & (ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY)) != 0 && "Must use ImGuiChildFlags_AutoResizeX or ImGuiChildFlags_AutoResizeY with ImGuiChildFlags_AlwaysAutoResize!");
6512 }
6513#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
6514 if (window_flags & ImGuiWindowFlags_AlwaysUseWindowPadding)
6516 if (window_flags & ImGuiWindowFlags_NavFlattened)
6517 child_flags |= ImGuiChildFlags_NavFlattened;
6518#endif
6519 if (child_flags & ImGuiChildFlags_AutoResizeX)
6520 child_flags &= ~ImGuiChildFlags_ResizeX;
6521 if (child_flags & ImGuiChildFlags_AutoResizeY)
6522 child_flags &= ~ImGuiChildFlags_ResizeY;
6523
6524 // Set window flags
6526 window_flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag
6528 window_flags |= ImGuiWindowFlags_AlwaysAutoResize;
6529 if ((child_flags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY)) == 0)
6531
6532 // Special framed style
6533 if (child_flags & ImGuiChildFlags_FrameStyle)
6534 {
6540 window_flags |= ImGuiWindowFlags_NoMove;
6541 }
6542
6543 // Forward size
6544 // Important: Begin() has special processing to switch condition to ImGuiCond_FirstUseEver for a given axis when ImGuiChildFlags_ResizeXXX is set.
6545 // (the alternative would to store conditional flags per axis, which is possible but more code)
6546 const ImVec2 size_avail = GetContentRegionAvail();
6547 const ImVec2 size_default((child_flags & ImGuiChildFlags_AutoResizeX) ? 0.0f : size_avail.x, (child_flags & ImGuiChildFlags_AutoResizeY) ? 0.0f : size_avail.y);
6548 ImVec2 size = CalcItemSize(size_arg, size_default.x, size_default.y);
6549
6550 // A SetNextWindowSize() call always has priority (#8020)
6551 // (since the code in Begin() never supported SizeVal==0.0f aka auto-resize via SetNextWindowSize() call, we don't support it here for now)
6552 // FIXME: We only support ImGuiCond_Always in this path. Supporting other paths would requires to obtain window pointer.
6554 {
6555 if (g.NextWindowData.SizeVal.x > 0.0f)
6556 {
6557 size.x = g.NextWindowData.SizeVal.x;
6558 child_flags &= ~ImGuiChildFlags_ResizeX;
6559 }
6560 if (g.NextWindowData.SizeVal.y > 0.0f)
6561 {
6562 size.y = g.NextWindowData.SizeVal.y;
6563 child_flags &= ~ImGuiChildFlags_ResizeY;
6564 }
6565 }
6566 SetNextWindowSize(size);
6567
6568 // Forward child flags (we allow prior settings to merge but it'll only work for adding flags)
6570 g.NextWindowData.ChildFlags |= child_flags;
6571 else
6572 g.NextWindowData.ChildFlags = child_flags;
6574
6575 // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value.
6576 // FIXME: 2023/11/14: commented out shorted version. We had an issue with multiple ### in child window path names, which the trailing hash helped workaround.
6577 // e.g. "ParentName###ParentIdentifier/ChildName###ChildIdentifier" would get hashed incorrectly by ImHashStr(), trailing _%08X somehow fixes it.
6578 const char* temp_window_name;
6579 /*if (name && parent_window->IDStack.back() == parent_window->ID)
6580 ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%s", parent_window->Name, name); // May omit ID if in root of ID stack
6581 else*/
6582 if (name)
6583 ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%s_%08X", parent_window->Name, name, id);
6584 else
6585 ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%08X", parent_window->Name, id);
6586
6587 // Set style
6588 const float backup_border_size = g.Style.ChildBorderSize;
6589 if ((child_flags & ImGuiChildFlags_Borders) == 0)
6590 g.Style.ChildBorderSize = 0.0f;
6591
6592 // Begin into window
6593 const bool ret = Begin(temp_window_name, NULL, window_flags);
6594
6595 // Restore style
6596 g.Style.ChildBorderSize = backup_border_size;
6597 if (child_flags & ImGuiChildFlags_FrameStyle)
6598 {
6599 PopStyleVar(3);
6600 PopStyleColor();
6601 }
6602
6603 ImGuiWindow* child_window = g.CurrentWindow;
6604 child_window->ChildId = id;
6605
6606 // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually.
6607 // While this is not really documented/defined, it seems that the expected thing to do.
6608 if (child_window->BeginCount == 1)
6609 parent_window->DC.CursorPos = child_window->Pos;
6610
6611 // Process navigation-in immediately so NavInit can run on first frame
6612 // Can enter a child if (A) it has navigable items or (B) it can be scrolled.
6613 const ImGuiID temp_id_for_activation = ImHashStr("##Child", 0, id);
6614 if (g.ActiveId == temp_id_for_activation)
6615 ClearActiveID();
6616 if (g.NavActivateId == id && !(child_flags & ImGuiChildFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY))
6617 {
6618 FocusWindow(child_window);
6619 NavInitWindow(child_window, false);
6620 SetActiveID(temp_id_for_activation, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item
6622 }
6623 return ret;
6624}
6625
6627{
6628 ImGuiContext& g = *GImGui;
6629 ImGuiWindow* child_window = g.CurrentWindow;
6630
6631 const ImGuiID backup_within_end_child_id = g.WithinEndChildID;
6632 IM_ASSERT(child_window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() calls
6633
6634 g.WithinEndChildID = child_window->ID;
6635 ImVec2 child_size = child_window->Size;
6636 End();
6637 if (child_window->BeginCount == 1)
6638 {
6639 ImGuiWindow* parent_window = g.CurrentWindow;
6640 ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + child_size);
6641 ItemSize(child_size);
6642 const bool nav_flattened = (child_window->ChildFlags & ImGuiChildFlags_NavFlattened) != 0;
6643 if ((child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY) && !nav_flattened)
6644 {
6645 ItemAdd(bb, child_window->ChildId);
6646 RenderNavCursor(bb, child_window->ChildId);
6647
6648 // When browsing a window that has no activable items (scroll only) we keep a highlight on the child (pass g.NavId to trick into always displaying)
6649 if (child_window->DC.NavLayersActiveMask == 0 && child_window == g.NavWindow)
6651 }
6652 else
6653 {
6654 // Not navigable into
6655 // - This is a bit of a fringe use case, mostly useful for undecorated, non-scrolling contents childs, or empty childs.
6656 // - We could later decide to not apply this path if ImGuiChildFlags_FrameStyle or ImGuiChildFlags_Borders is set.
6657 ItemAdd(bb, child_window->ChildId, NULL, ImGuiItemFlags_NoNav);
6658
6659 // But when flattened we directly reach items, adjust active layer mask accordingly
6660 if (nav_flattened)
6661 parent_window->DC.NavLayersActiveMaskNext |= child_window->DC.NavLayersActiveMaskNext;
6662 }
6663 if (g.HoveredWindow == child_window)
6666 //SetLastItemDataForChildWindowItem(child_window, child_window->Rect()); // Not needed, effectively done by ItemAdd()
6667 }
6668 else
6669 {
6670 SetLastItemDataForChildWindowItem(child_window, child_window->Rect());
6671 }
6672
6673 g.WithinEndChildID = backup_within_end_child_id;
6674 g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
6675}
6676
6677static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
6678{
6679 window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags);
6680 window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags);
6681 window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags);
6682 window->SetWindowDockAllowFlags = enabled ? (window->SetWindowDockAllowFlags | flags) : (window->SetWindowDockAllowFlags & ~flags);
6683}
6684
6686{
6687 ImGuiContext& g = *GImGui;
6688 return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id);
6689}
6690
6692{
6693 ImGuiID id = ImHashStr(name);
6694 return FindWindowByID(id);
6695}
6696
6698{
6699 const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
6700 window->ViewportPos = main_viewport->Pos;
6701 if (settings->ViewportId)
6702 {
6703 window->ViewportId = settings->ViewportId;
6704 window->ViewportPos = ImVec2(settings->ViewportPos.x, settings->ViewportPos.y);
6705 }
6706 window->Pos = ImTrunc(ImVec2(settings->Pos.x + window->ViewportPos.x, settings->Pos.y + window->ViewportPos.y));
6707 if (settings->Size.x > 0 && settings->Size.y > 0)
6708 window->Size = window->SizeFull = ImTrunc(ImVec2(settings->Size.x, settings->Size.y));
6709 window->Collapsed = settings->Collapsed;
6710 window->DockId = settings->DockId;
6711 window->DockOrder = settings->DockOrder;
6712}
6713
6715{
6716 // Initial window state with e.g. default/arbitrary window position
6717 // Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
6718 const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
6719 window->Pos = main_viewport->Pos + ImVec2(60, 60);
6720 window->Size = window->SizeFull = ImVec2(0, 0);
6721 window->ViewportPos = main_viewport->Pos;
6723
6724 if (settings != NULL)
6725 {
6727 ApplyWindowSettings(window, settings);
6728 }
6729 window->DC.CursorStartPos = window->DC.CursorMaxPos = window->DC.IdealMaxPos = window->Pos; // So first call to CalcWindowContentSizes() doesn't return crazy values
6730
6731 if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
6732 {
6733 window->AutoFitFramesX = window->AutoFitFramesY = 2;
6734 window->AutoFitOnlyGrows = false;
6735 }
6736 else
6737 {
6738 if (window->Size.x <= 0.0f)
6739 window->AutoFitFramesX = 2;
6740 if (window->Size.y <= 0.0f)
6741 window->AutoFitFramesY = 2;
6742 window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
6743 }
6744}
6745
6746static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
6747{
6748 // Create window the first time
6749 //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags);
6750 ImGuiContext& g = *GImGui;
6751 ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
6752 window->Flags = flags;
6753 g.WindowsById.SetVoidPtr(window->ID, window);
6754
6755 ImGuiWindowSettings* settings = NULL;
6756 if (!(flags & ImGuiWindowFlags_NoSavedSettings))
6757 if ((settings = ImGui::FindWindowSettingsByWindow(window)) != 0)
6758 window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
6759
6760 InitOrLoadWindowSettings(window, settings);
6761
6763 g.Windows.push_front(window); // Quite slow but rare and only once
6764 else
6765 g.Windows.push_back(window);
6766
6767 return window;
6768}
6769
6771{
6772 return window->DockNodeAsHost ? window->DockNodeAsHost->VisibleWindow : window;
6773}
6774
6776{
6777 return (window->DockNodeAsHost && window->DockNodeAsHost->VisibleWindow) ? window->DockNodeAsHost->VisibleWindow : window;
6778}
6779
6781{
6782 // We give windows non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups)
6783 // FIXME: Essentially we want to restrict manual resizing to WindowMinSize+Decoration, and allow api resizing to be smaller.
6784 // Perhaps should tend further a neater test for this.
6785 ImGuiContext& g = *GImGui;
6786 ImVec2 size_min;
6787 if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Popup))
6788 {
6789 size_min.x = (window->ChildFlags & ImGuiChildFlags_ResizeX) ? g.Style.WindowMinSize.x : 4.0f;
6790 size_min.y = (window->ChildFlags & ImGuiChildFlags_ResizeY) ? g.Style.WindowMinSize.y : 4.0f;
6791 }
6792 else
6793 {
6794 size_min.x = ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) == 0) ? g.Style.WindowMinSize.x : 4.0f;
6795 size_min.y = ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) == 0) ? g.Style.WindowMinSize.y : 4.0f;
6796 }
6797
6798 // Reduce artifacts with very small windows
6799 ImGuiWindow* window_for_height = GetWindowForTitleAndMenuHeight(window);
6800 size_min.y = ImMax(size_min.y, window_for_height->TitleBarHeight + window_for_height->MenuBarHeight + ImMax(0.0f, g.Style.WindowRounding - 1.0f));
6801 return size_min;
6802}
6803
6804static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& size_desired)
6805{
6806 ImGuiContext& g = *GImGui;
6807 ImVec2 new_size = size_desired;
6809 {
6810 // See comments in SetNextWindowSizeConstraints() for details about setting size_min an size_max.
6812 new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
6813 new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
6815 {
6818 data.Pos = window->Pos;
6819 data.CurrentSize = window->SizeFull;
6820 data.DesiredSize = new_size;
6822 new_size = data.DesiredSize;
6823 }
6824 new_size.x = IM_TRUNC(new_size.x);
6825 new_size.y = IM_TRUNC(new_size.y);
6826 }
6827
6828 // Minimum size
6829 ImVec2 size_min = CalcWindowMinSize(window);
6830 return ImMax(new_size, size_min);
6831}
6832
6833static void CalcWindowContentSizes(ImGuiWindow* window, ImVec2* content_size_current, ImVec2* content_size_ideal)
6834{
6835 bool preserve_old_content_sizes = false;
6836 if (window->Collapsed && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
6837 preserve_old_content_sizes = true;
6838 else if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0)
6839 preserve_old_content_sizes = true;
6840 if (preserve_old_content_sizes)
6841 {
6842 *content_size_current = window->ContentSize;
6843 *content_size_ideal = window->ContentSizeIdeal;
6844 return;
6845 }
6846
6847 content_size_current->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : ImTrunc64(window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);
6848 content_size_current->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : ImTrunc64(window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);
6849 content_size_ideal->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : ImTrunc64(ImMax(window->DC.CursorMaxPos.x, window->DC.IdealMaxPos.x) - window->DC.CursorStartPos.x);
6850 content_size_ideal->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : ImTrunc64(ImMax(window->DC.CursorMaxPos.y, window->DC.IdealMaxPos.y) - window->DC.CursorStartPos.y);
6851}
6852
6853static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents)
6854{
6855 ImGuiContext& g = *GImGui;
6856 ImGuiStyle& style = g.Style;
6857 const float decoration_w_without_scrollbars = window->DecoOuterSizeX1 + window->DecoOuterSizeX2 - window->ScrollbarSizes.x;
6858 const float decoration_h_without_scrollbars = window->DecoOuterSizeY1 + window->DecoOuterSizeY2 - window->ScrollbarSizes.y;
6859 ImVec2 size_pad = window->WindowPadding * 2.0f;
6860 ImVec2 size_desired = size_contents + size_pad + ImVec2(decoration_w_without_scrollbars, decoration_h_without_scrollbars);
6861
6862 // Determine maximum window size
6863 // Child windows are layed within their parent (unless they are also popups/menus) and thus have no restriction
6864 ImVec2 size_max = ImVec2(FLT_MAX, FLT_MAX);
6865 if ((window->Flags & ImGuiWindowFlags_ChildWindow) == 0 || (window->Flags & ImGuiWindowFlags_Popup) != 0)
6866 {
6867 if (!window->ViewportOwned)
6868 size_max = ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f;
6869 const int monitor_idx = window->ViewportAllowPlatformMonitorExtend;
6870 if (monitor_idx >= 0 && monitor_idx < g.PlatformIO.Monitors.Size)
6871 size_max = g.PlatformIO.Monitors[monitor_idx].WorkSize - style.DisplaySafeAreaPadding * 2.0f;
6872 }
6873
6874 if (window->Flags & ImGuiWindowFlags_Tooltip)
6875 {
6876 // Tooltip always resize (up to maximum size)
6877 return ImMin(size_desired, size_max);
6878 }
6879 else
6880 {
6881 ImVec2 size_min = CalcWindowMinSize(window);
6882 ImVec2 size_auto_fit = ImClamp(size_desired, ImMin(size_min, size_max), size_max);
6883
6884 // FIXME: CalcWindowAutoFitSize() doesn't take into account that only one axis may be auto-fit when calculating scrollbars,
6885 // we may need to compute/store three variants of size_auto_fit, for x/y/xy.
6886 // Here we implement a workaround for child windows only, but a full solution would apply to normal windows as well:
6888 size_auto_fit.y = window->SizeFull.y;
6890 size_auto_fit.x = window->SizeFull.x;
6891
6892 // When the window cannot fit all contents (either because of constraints, either because screen is too small),
6893 // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
6894 ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);
6895 bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - decoration_w_without_scrollbars < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
6896 bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_h_without_scrollbars < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
6897 if (will_have_scrollbar_x)
6898 size_auto_fit.y += style.ScrollbarSize;
6899 if (will_have_scrollbar_y)
6900 size_auto_fit.x += style.ScrollbarSize;
6901 return size_auto_fit;
6902 }
6903}
6904
6906{
6907 ImVec2 size_contents_current;
6908 ImVec2 size_contents_ideal;
6909 CalcWindowContentSizes(window, &size_contents_current, &size_contents_ideal);
6910 ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents_ideal);
6911 ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit);
6912 return size_final;
6913}
6914
6916{
6918 return ImGuiCol_PopupBg;
6919 if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !window->DockIsActive)
6920 return ImGuiCol_ChildBg;
6921 return ImGuiCol_WindowBg;
6922}
6923
6924static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)
6925{
6926 ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left
6927 ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right
6928 ImVec2 size_expected = pos_max - pos_min;
6929 ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected);
6930 *out_pos = pos_min;
6931 if (corner_norm.x == 0.0f)
6932 out_pos->x -= (size_constrained.x - size_expected.x);
6933 if (corner_norm.y == 0.0f)
6934 out_pos->y -= (size_constrained.y - size_expected.y);
6935 *out_size = size_constrained;
6936}
6937
6938// Data for resizing from resize grip / corner
6940{
6944};
6946{
6947 { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 }, // Lower-right
6948 { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 }, // Lower-left
6949 { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 }, // Upper-left (Unused)
6950 { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 } // Upper-right (Unused)
6951};
6952
6953// Data for resizing from borders
6955{
6956 ImVec2 InnerDir; // Normal toward inside
6957 ImVec2 SegmentN1, SegmentN2; // End positions, normalized (0,0: upper left)
6958 float OuterAngle; // Angle toward outside
6959};
6961{
6962 { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f }, // Left
6963 { ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right
6964 { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Up
6965 { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f } // Down
6966};
6967
6968static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
6969{
6970 ImRect rect = window->Rect();
6971 if (thickness == 0.0f)
6972 rect.Max -= ImVec2(1, 1);
6973 if (border_n == ImGuiDir_Left) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); }
6974 if (border_n == ImGuiDir_Right) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); }
6975 if (border_n == ImGuiDir_Up) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); }
6976 if (border_n == ImGuiDir_Down) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); }
6977 IM_ASSERT(0);
6978 return ImRect();
6979}
6980
6981// 0..3: corners (Lower-right, Lower-left, Unused, Unused)
6983{
6984 IM_ASSERT(n >= 0 && n < 4);
6985 ImGuiID id = window->DockIsActive ? window->DockNode->HostWindow->ID : window->ID;
6986 id = ImHashStr("#RESIZE", 0, id);
6987 id = ImHashData(&n, sizeof(int), id);
6988 return id;
6989}
6990
6991// Borders (Left, Right, Up, Down)
6993{
6994 IM_ASSERT(dir >= 0 && dir < 4);
6995 int n = (int)dir + 4;
6996 ImGuiID id = window->DockIsActive ? window->DockNode->HostWindow->ID : window->ID;
6997 id = ImHashStr("#RESIZE", 0, id);
6998 id = ImHashData(&n, sizeof(int), id);
6999 return id;
7000}
7001
7002// Handle resize for: Resize Grips, Borders, Gamepad
7003// Return true when using auto-fit (double-click on resize grip)
7004static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_hovered, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect)
7005{
7006 ImGuiContext& g = *GImGui;
7007 ImGuiWindowFlags flags = window->Flags;
7008
7009 if ((flags & ImGuiWindowFlags_NoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
7010 return false;
7012 return false;
7013 if (window->WasActive == false) // Early out to avoid running this code for e.g. a hidden implicit/fallback Debug window.
7014 return false;
7015
7016 int ret_auto_fit_mask = 0x00;
7017 const float grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
7018 const float grip_hover_inner_size = (resize_grip_count > 0) ? IM_TRUNC(grip_draw_size * 0.75f) : 0.0f;
7019 const float grip_hover_outer_size = g.WindowsBorderHoverPadding;
7020
7021 ImRect clamp_rect = visibility_rect;
7022 const bool window_move_from_title_bar = g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar);
7023 if (window_move_from_title_bar)
7024 clamp_rect.Min.y -= window->TitleBarHeight;
7025
7026 ImVec2 pos_target(FLT_MAX, FLT_MAX);
7027 ImVec2 size_target(FLT_MAX, FLT_MAX);
7028
7029 // Clip mouse interaction rectangles within the viewport rectangle (in practice the narrowing is going to happen most of the time).
7030 // - Not narrowing would mostly benefit the situation where OS windows _without_ decoration have a threshold for hovering when outside their limits.
7031 // This is however not the case with current backends under Win32, but a custom borderless window implementation would benefit from it.
7032 // - When decoration are enabled we typically benefit from that distance, but then our resize elements would be conflicting with OS resize elements, so we also narrow.
7033 // - Note that we are unable to tell if the platform setup allows hovering with a distance threshold (on Win32, decorated window have such threshold).
7034 // We only clip interaction so we overwrite window->ClipRect, cannot call PushClipRect() yet as DrawList is not yet setup.
7035 const bool clip_with_viewport_rect = !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) || (g.IO.MouseHoveredViewport != window->ViewportId) || !(window->Viewport->Flags & ImGuiViewportFlags_NoDecoration);
7036 if (clip_with_viewport_rect)
7037 window->ClipRect = window->Viewport->GetMainRect();
7038
7039 // Resize grips and borders are on layer 1
7041
7042 // Manual resize grips
7043 PushID("#RESIZE");
7044 for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
7045 {
7046 const ImGuiResizeGripDef& def = resize_grip_def[resize_grip_n];
7047 const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, def.CornerPosN);
7048
7049 // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
7050 bool hovered, held;
7051 ImRect resize_rect(corner - def.InnerDir * grip_hover_outer_size, corner + def.InnerDir * grip_hover_inner_size);
7052 if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
7053 if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
7054 ImGuiID resize_grip_id = window->GetID(resize_grip_n); // == GetWindowResizeCornerID()
7055 ItemAdd(resize_rect, resize_grip_id, NULL, ImGuiItemFlags_NoNav);
7056 ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
7057 //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
7058 if (hovered || held)
7060
7061 if (held && g.IO.MouseDoubleClicked[0])
7062 {
7063 // Auto-fit when double-clicking
7064 size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit);
7065 ret_auto_fit_mask = 0x03; // Both axes
7066 ClearActiveID();
7067 }
7068 else if (held)
7069 {
7070 // Resize from any of the four corners
7071 // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
7072 ImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? clamp_rect.Min.x : -FLT_MAX, (def.CornerPosN.y == 1.0f || (def.CornerPosN.y == 0.0f && window_move_from_title_bar)) ? clamp_rect.Min.y : -FLT_MAX);
7073 ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? clamp_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? clamp_rect.Max.y : +FLT_MAX);
7074 ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip
7075 corner_target = ImClamp(corner_target, clamp_min, clamp_max);
7076 CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target);
7077 }
7078
7079 // Only lower-left grip is visible before hovering/activating
7080 if (resize_grip_n == 0 || held || hovered)
7081 resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
7082 }
7083
7084 int resize_border_mask = 0x00;
7085 if (window->Flags & ImGuiWindowFlags_ChildWindow)
7086 resize_border_mask |= ((window->ChildFlags & ImGuiChildFlags_ResizeX) ? 0x02 : 0) | ((window->ChildFlags & ImGuiChildFlags_ResizeY) ? 0x08 : 0);
7087 else
7088 resize_border_mask = g.IO.ConfigWindowsResizeFromEdges ? 0x0F : 0x00;
7089 for (int border_n = 0; border_n < 4; border_n++)
7090 {
7091 if ((resize_border_mask & (1 << border_n)) == 0)
7092 continue;
7093 const ImGuiResizeBorderDef& def = resize_border_def[border_n];
7094 const ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y;
7095
7096 bool hovered, held;
7097 ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, g.WindowsBorderHoverPadding);
7098 ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID()
7099 ItemAdd(border_rect, border_id, NULL, ImGuiItemFlags_NoNav);
7100 ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
7101 //GetForegroundDrawList(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
7103 hovered = false;
7104 if (hovered || held)
7106 if (held && g.IO.MouseDoubleClicked[0])
7107 {
7108 // Double-clicking bottom or right border auto-fit on this axis
7109 // FIXME: CalcWindowAutoFitSize() doesn't take into account that only one side may be auto-fit when calculating scrollbars.
7110 // FIXME: Support top and right borders: rework CalcResizePosSizeFromAnyCorner() to be reusable in both cases.
7111 if (border_n == 1 || border_n == 3) // Right and bottom border
7112 {
7113 size_target[axis] = CalcWindowSizeAfterConstraint(window, size_auto_fit)[axis];
7114 ret_auto_fit_mask |= (1 << axis);
7115 hovered = held = false; // So border doesn't show highlighted at new position
7116 }
7117 ClearActiveID();
7118 }
7119 else if (held)
7120 {
7121 // Switch to relative resizing mode when border geometry moved (e.g. resizing a child altering parent scroll), in order to avoid resizing feedback loop.
7122 // Currently only using relative mode on resizable child windows, as the problem to solve is more likely noticeable for them, but could apply for all windows eventually.
7123 // FIXME: May want to generalize this idiom at lower-level, so more widgets can use it!
7124 const bool just_scrolled_manually_while_resizing = (g.WheelingWindow != NULL && g.WheelingWindowScrolledFrame == g.FrameCount && IsWindowChildOf(window, g.WheelingWindow, false, true));
7125 if (g.ActiveIdIsJustActivated || just_scrolled_manually_while_resizing)
7126 {
7127 g.WindowResizeBorderExpectedRect = border_rect;
7128 g.WindowResizeRelativeMode = false;
7129 }
7130 if ((window->Flags & ImGuiWindowFlags_ChildWindow) && memcmp(&g.WindowResizeBorderExpectedRect, &border_rect, sizeof(ImRect)) != 0)
7131 g.WindowResizeRelativeMode = true;
7132
7133 const ImVec2 border_curr = (window->Pos + ImMin(def.SegmentN1, def.SegmentN2) * window->Size);
7134 const float border_target_rel_mode_for_axis = border_curr[axis] + g.IO.MouseDelta[axis];
7135 const float border_target_abs_mode_for_axis = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + g.WindowsBorderHoverPadding; // Match ButtonBehavior() padding above.
7136
7137 // Use absolute mode position
7138 ImVec2 border_target = window->Pos;
7139 border_target[axis] = border_target_abs_mode_for_axis;
7140
7141 // Use relative mode target for child window, ignore resize when moving back toward the ideal absolute position.
7142 bool ignore_resize = false;
7144 {
7145 //GetForegroundDrawList()->AddText(GetMainViewport()->WorkPos, IM_COL32_WHITE, "Relative Mode");
7146 border_target[axis] = border_target_rel_mode_for_axis;
7147 if (g.IO.MouseDelta[axis] == 0.0f || (g.IO.MouseDelta[axis] > 0.0f) == (border_target_rel_mode_for_axis > border_target_abs_mode_for_axis))
7148 ignore_resize = true;
7149 }
7150
7151 // Clamp, apply
7152 ImVec2 clamp_min(border_n == ImGuiDir_Right ? clamp_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down || (border_n == ImGuiDir_Up && window_move_from_title_bar) ? clamp_rect.Min.y : -FLT_MAX);
7153 ImVec2 clamp_max(border_n == ImGuiDir_Left ? clamp_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? clamp_rect.Max.y : +FLT_MAX);
7154 border_target = ImClamp(border_target, clamp_min, clamp_max);
7155 if (flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent
7156 {
7157 ImGuiWindow* parent_window = window->ParentWindow;
7158 ImGuiWindowFlags parent_flags = parent_window->Flags;
7159 ImRect border_limit_rect = parent_window->InnerRect;
7160 border_limit_rect.Expand(ImVec2(-ImMax(parent_window->WindowPadding.x, parent_window->WindowBorderSize), -ImMax(parent_window->WindowPadding.y, parent_window->WindowBorderSize)));
7162 border_target.x = ImClamp(border_target.x, border_limit_rect.Min.x, border_limit_rect.Max.x);
7163 if ((axis == ImGuiAxis_Y) && (parent_flags & ImGuiWindowFlags_NoScrollbar))
7164 border_target.y = ImClamp(border_target.y, border_limit_rect.Min.y, border_limit_rect.Max.y);
7165 }
7166 if (!ignore_resize)
7167 CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target);
7168 }
7169 if (hovered)
7170 *border_hovered = border_n;
7171 if (held)
7172 *border_held = border_n;
7173 }
7174 PopID();
7175
7176 // Restore nav layer
7178
7179 // Navigation resize (keyboard/gamepad)
7180 // FIXME: This cannot be moved to NavUpdateWindowing() because CalcWindowSizeAfterConstraint() need to callback into user.
7181 // Not even sure the callback works here.
7183 {
7184 ImVec2 nav_resize_dir;
7189 if (nav_resize_dir.x != 0.0f || nav_resize_dir.y != 0.0f)
7190 {
7191 const float NAV_RESIZE_SPEED = 600.0f;
7192 const float resize_step = NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y);
7193 g.NavWindowingAccumDeltaSize += nav_resize_dir * resize_step;
7194 g.NavWindowingAccumDeltaSize = ImMax(g.NavWindowingAccumDeltaSize, clamp_rect.Min - window->Pos - window->Size); // We need Pos+Size >= clmap_rect.Min, so Size >= clmap_rect.Min - Pos, so size_delta >= clmap_rect.Min - window->Pos - window->Size
7195 g.NavWindowingToggleLayer = false;
7196 g.NavHighlightItemUnderNav = true;
7197 resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
7198 ImVec2 accum_floored = ImTrunc(g.NavWindowingAccumDeltaSize);
7199 if (accum_floored.x != 0.0f || accum_floored.y != 0.0f)
7200 {
7201 // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
7202 size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + accum_floored);
7203 g.NavWindowingAccumDeltaSize -= accum_floored;
7204 }
7205 }
7206 }
7207
7208 // Apply back modified position/size to window
7209 const ImVec2 curr_pos = window->Pos;
7210 const ImVec2 curr_size = window->SizeFull;
7211 if (size_target.x != FLT_MAX && (window->Size.x != size_target.x || window->SizeFull.x != size_target.x))
7212 window->Size.x = window->SizeFull.x = size_target.x;
7213 if (size_target.y != FLT_MAX && (window->Size.y != size_target.y || window->SizeFull.y != size_target.y))
7214 window->Size.y = window->SizeFull.y = size_target.y;
7215 if (pos_target.x != FLT_MAX && window->Pos.x != ImTrunc(pos_target.x))
7216 window->Pos.x = ImTrunc(pos_target.x);
7217 if (pos_target.y != FLT_MAX && window->Pos.y != ImTrunc(pos_target.y))
7218 window->Pos.y = ImTrunc(pos_target.y);
7219 if (curr_pos.x != window->Pos.x || curr_pos.y != window->Pos.y || curr_size.x != window->SizeFull.x || curr_size.y != window->SizeFull.y)
7220 MarkIniSettingsDirty(window);
7221
7222 // Recalculate next expected border expected coordinates
7223 if (*border_held != -1)
7224 g.WindowResizeBorderExpectedRect = GetResizeBorderRect(window, *border_held, grip_hover_inner_size, g.WindowsBorderHoverPadding);
7225
7226 return ret_auto_fit_mask;
7227}
7228
7229static inline void ClampWindowPos(ImGuiWindow* window, const ImRect& visibility_rect)
7230{
7231 ImGuiContext& g = *GImGui;
7232 ImVec2 size_for_clamping = window->Size;
7234 size_for_clamping.y = ImGui::GetFrameHeight(); // Not using window->TitleBarHeight() as DockNodeAsHost will report 0.0f here.
7236 size_for_clamping.y = window->TitleBarHeight;
7237 window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);
7238}
7239
7240static void RenderWindowOuterSingleBorder(ImGuiWindow* window, int border_n, ImU32 border_col, float border_size)
7241{
7242 const ImGuiResizeBorderDef& def = resize_border_def[border_n];
7243 const float rounding = window->WindowRounding;
7244 const ImRect border_r = GetResizeBorderRect(window, border_n, rounding, 0.0f);
7245 window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle);
7246 window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f);
7247 window->DrawList->PathStroke(border_col, ImDrawFlags_None, border_size);
7248}
7249
7251{
7252 ImGuiContext& g = *GImGui;
7253 const float border_size = window->WindowBorderSize;
7254 const ImU32 border_col = GetColorU32(ImGuiCol_Border);
7255 if (border_size > 0.0f && (window->Flags & ImGuiWindowFlags_NoBackground) == 0)
7256 window->DrawList->AddRect(window->Pos, window->Pos + window->Size, border_col, window->WindowRounding, 0, window->WindowBorderSize);
7257 else if (border_size > 0.0f)
7258 {
7259 if (window->ChildFlags & ImGuiChildFlags_ResizeX) // Similar code as 'resize_border_mask' computation in UpdateWindowManualResize() but we specifically only always draw explicit child resize border.
7260 RenderWindowOuterSingleBorder(window, 1, border_col, border_size);
7261 if (window->ChildFlags & ImGuiChildFlags_ResizeY)
7262 RenderWindowOuterSingleBorder(window, 3, border_col, border_size);
7263 }
7264 if (window->ResizeBorderHovered != -1 || window->ResizeBorderHeld != -1)
7265 {
7266 const int border_n = (window->ResizeBorderHeld != -1) ? window->ResizeBorderHeld : window->ResizeBorderHovered;
7267 const ImU32 border_col_resizing = GetColorU32((window->ResizeBorderHeld != -1) ? ImGuiCol_SeparatorActive : ImGuiCol_SeparatorHovered);
7268 RenderWindowOuterSingleBorder(window, border_n, border_col_resizing, ImMax(2.0f, window->WindowBorderSize)); // Thicker than usual
7269 }
7270 if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive)
7271 {
7272 float y = window->Pos.y + window->TitleBarHeight - 1;
7273 window->DrawList->AddLine(ImVec2(window->Pos.x + border_size * 0.5f, y), ImVec2(window->Pos.x + window->Size.x - border_size * 0.5f, y), border_col, g.Style.FrameBorderSize);
7274 }
7275}
7276
7277// Draw background and borders
7278// Draw and handle scrollbars
7279void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size)
7280{
7281 ImGuiContext& g = *GImGui;
7282 ImGuiStyle& style = g.Style;
7283 ImGuiWindowFlags flags = window->Flags;
7284
7285 // Ensure that Scrollbar() doesn't read last frame's SkipItems
7286 IM_ASSERT(window->BeginCount == 0);
7287 window->SkipItems = false;
7289
7290 // Draw window + handle manual resize
7291 // As we highlight the title bar when want_focus is set, multiple reappearing windows will have their title bar highlighted on their reappearing frame.
7292 const float window_rounding = window->WindowRounding;
7293 const float window_border_size = window->WindowBorderSize;
7294 if (window->Collapsed)
7295 {
7296 // Title bar only
7297 const float backup_border_size = style.FrameBorderSize;
7299 ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && g.NavCursorVisible) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
7300 if (window->ViewportOwned)
7301 title_bar_col |= IM_COL32_A_MASK; // No alpha (we don't support is_docking_transparent_payload here because simpler and less meaningful, but could with a bit of code shuffle/reuse)
7302 RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
7303 g.Style.FrameBorderSize = backup_border_size;
7304 }
7305 else
7306 {
7307 // Window background
7308 if (!(flags & ImGuiWindowFlags_NoBackground))
7309 {
7310 bool is_docking_transparent_payload = false;
7313 is_docking_transparent_payload = true;
7314
7315 ImU32 bg_col = GetColorU32(GetWindowBgColorIdx(window));
7316 if (window->ViewportOwned)
7317 {
7318 bg_col |= IM_COL32_A_MASK; // No alpha
7319 if (is_docking_transparent_payload)
7321 }
7322 else
7323 {
7324 // Adjust alpha. For docking
7325 bool override_alpha = false;
7326 float alpha = 1.0f;
7328 {
7329 alpha = g.NextWindowData.BgAlphaVal;
7330 override_alpha = true;
7331 }
7332 if (is_docking_transparent_payload)
7333 {
7334 alpha *= DOCKING_TRANSPARENT_PAYLOAD_ALPHA; // FIXME-DOCK: Should that be an override?
7335 override_alpha = true;
7336 }
7337 if (override_alpha)
7338 bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
7339 }
7340
7341 // Render, for docked windows and host windows we ensure bg goes before decorations
7342 if (window->DockIsActive)
7343 window->DockNode->LastBgColor = bg_col;
7344 ImDrawList* bg_draw_list = window->DockIsActive ? window->DockNode->HostWindow->DrawList : window->DrawList;
7345 if (window->DockIsActive || (flags & ImGuiWindowFlags_DockNodeHost))
7347 bg_draw_list->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom);
7348 if (window->DockIsActive || (flags & ImGuiWindowFlags_DockNodeHost))
7350 }
7351 if (window->DockIsActive)
7352 window->DockNode->IsBgDrawnThisFrame = true;
7353
7354 // Title bar
7355 // (when docked, DockNode are drawing their own title bar. Individual windows however do NOT set the _NoTitleBar flag,
7356 // in order for their pos/size to be matching their undocking state.)
7357 if (!(flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive)
7358 {
7359 ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
7360 if (window->ViewportOwned)
7361 title_bar_col |= IM_COL32_A_MASK; // No alpha
7362 window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawFlags_RoundCornersTop);
7363 }
7364
7365 // Menu bar
7366 if (flags & ImGuiWindowFlags_MenuBar)
7367 {
7368 ImRect menu_bar_rect = window->MenuBarRect();
7369 menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
7370 window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop);
7371 if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
7372 window->DrawList->AddLine(menu_bar_rect.GetBL() + ImVec2(window_border_size * 0.5f, 0.0f), menu_bar_rect.GetBR() - ImVec2(window_border_size * 0.5f, 0.0f), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
7373 }
7374
7375 // Docking: Unhide tab bar (small triangle in the corner), drag from small triangle to quickly undock
7376 ImGuiDockNode* node = window->DockNode;
7377 if (window->DockIsActive && node->IsHiddenTabBar() && !node->IsNoTabBar())
7378 {
7379 float unhide_sz_draw = ImTrunc(g.FontSize * 0.70f);
7380 float unhide_sz_hit = ImTrunc(g.FontSize * 0.55f);
7381 ImVec2 p = node->Pos;
7382 ImRect r(p, p + ImVec2(unhide_sz_hit, unhide_sz_hit));
7383 ImGuiID unhide_id = window->GetID("#UNHIDE");
7384 KeepAliveID(unhide_id);
7385 bool hovered, held;
7386 if (ButtonBehavior(r, unhide_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren))
7387 node->WantHiddenTabBarToggle = true;
7388 else if (held && IsMouseDragging(0))
7389 StartMouseMovingWindowOrNode(window, node, true); // Undock from tab-bar triangle = same as window/collapse menu button
7390
7391 // FIXME-DOCK: Ideally we'd use ImGuiCol_TitleBgActive/ImGuiCol_TitleBg here, but neither is guaranteed to be visible enough at this sort of size..
7392 ImU32 col = GetColorU32(((held && hovered) || (node->IsFocused && !hovered)) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
7393 window->DrawList->AddTriangleFilled(p, p + ImVec2(unhide_sz_draw, 0.0f), p + ImVec2(0.0f, unhide_sz_draw), col);
7394 }
7395
7396 // Scrollbars
7397 if (window->ScrollbarX)
7399 if (window->ScrollbarY)
7401
7402 // Render resize grips (after their input handling so we don't have a frame of latency)
7403 if (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize))
7404 {
7405 for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
7406 {
7407 const ImU32 col = resize_grip_col[resize_grip_n];
7408 if ((col & IM_COL32_A_MASK) == 0)
7409 continue;
7410 const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
7411 const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
7412 const float border_inner = IM_ROUND(window_border_size * 0.5f);
7413 window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(border_inner, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, border_inner)));
7414 window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, border_inner) : ImVec2(border_inner, resize_grip_draw_size)));
7415 window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + border_inner), corner.y + grip.InnerDir.y * (window_rounding + border_inner)), window_rounding, grip.AngleMin12, grip.AngleMax12);
7416 window->DrawList->PathFillConvex(col);
7417 }
7418 }
7419
7420 // Borders (for dock node host they will be rendered over after the tab bar)
7421 if (handle_borders_and_resize_grips && !window->DockNodeAsHost)
7423 }
7425}
7426
7427// When inside a dock node, this is handled in DockNodeCalcTabBarLayout() instead.
7428// Render title text, collapse button, close button
7429void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)
7430{
7431 ImGuiContext& g = *GImGui;
7432 ImGuiStyle& style = g.Style;
7433 ImGuiWindowFlags flags = window->Flags;
7434
7435 const bool has_close_button = (p_open != NULL);
7436 const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
7437
7438 // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
7439 // FIXME-NAV: Might want (or not?) to set the equivalent of ImGuiButtonFlags_NoNavFocus so that mouse clicks on standard title bar items don't necessarily set nav/keyboard ref?
7440 const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags;
7443
7444 // Layout buttons
7445 // FIXME: Would be nice to generalize the subtleties expressed here into reusable code.
7446 float pad_l = style.FramePadding.x;
7447 float pad_r = style.FramePadding.x;
7448 float button_sz = g.FontSize;
7449 ImVec2 close_button_pos;
7450 ImVec2 collapse_button_pos;
7451 if (has_close_button)
7452 {
7453 close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);
7454 pad_r += button_sz + style.ItemInnerSpacing.x;
7455 }
7456 if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
7457 {
7458 collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);
7459 pad_r += button_sz + style.ItemInnerSpacing.x;
7460 }
7461 if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
7462 {
7463 collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y + style.FramePadding.y);
7464 pad_l += button_sz + style.ItemInnerSpacing.x;
7465 }
7466
7467 // Collapse button (submitting first so it gets priority when choosing a navigation init fallback)
7468 if (has_collapse_button)
7469 if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos, NULL))
7470 window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function
7471
7472 // Close button
7473 if (has_close_button)
7474 {
7476 if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
7477 *p_open = false;
7478 g.CurrentItemFlags &= ~ImGuiItemFlags_NoFocus;
7479 }
7480
7482 g.CurrentItemFlags = item_flags_backup;
7483
7484 // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
7485 // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code..
7486 const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? button_sz * 0.80f : 0.0f;
7487 const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
7488
7489 // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button,
7490 // while uncentered title text will still reach edges correctly.
7491 if (pad_l > style.FramePadding.x)
7492 pad_l += g.Style.ItemInnerSpacing.x;
7493 if (pad_r > style.FramePadding.x)
7494 pad_r += g.Style.ItemInnerSpacing.x;
7495 if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f)
7496 {
7497 float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center
7498 float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x);
7499 pad_l = ImMax(pad_l, pad_extend * centerness);
7500 pad_r = ImMax(pad_r, pad_extend * centerness);
7501 }
7502
7503 ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y);
7504 ImRect clip_r(layout_r.Min.x, layout_r.Min.y, ImMin(layout_r.Max.x + g.Style.ItemInnerSpacing.x, title_bar_rect.Max.x), layout_r.Max.y);
7506 {
7507 ImVec2 marker_pos;
7508 marker_pos.x = ImClamp(layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x + text_size.x, layout_r.Min.x, layout_r.Max.x);
7509 marker_pos.y = (layout_r.Min.y + layout_r.Max.y) * 0.5f;
7510 if (marker_pos.x > layout_r.Min.x)
7511 {
7512 RenderBullet(window->DrawList, marker_pos, GetColorU32(ImGuiCol_Text));
7513 clip_r.Max.x = ImMin(clip_r.Max.x, marker_pos.x - (int)(marker_size_x * 0.5f));
7514 }
7515 }
7516 //if (g.IO.KeyShift) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
7517 //if (g.IO.KeyCtrl) window->DrawList->AddRect(clip_r.Min, clip_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
7518 RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
7519}
7520
7522{
7523 window->ParentWindow = parent_window;
7524 window->RootWindow = window->RootWindowPopupTree = window->RootWindowDockTree = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window;
7525 if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
7526 {
7527 window->RootWindowDockTree = parent_window->RootWindowDockTree;
7528 if (!window->DockIsActive && !(parent_window->Flags & ImGuiWindowFlags_DockNodeHost))
7529 window->RootWindow = parent_window->RootWindow;
7530 }
7531 if (parent_window && (flags & ImGuiWindowFlags_Popup))
7532 window->RootWindowPopupTree = parent_window->RootWindowPopupTree;
7533 if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) // FIXME: simply use _NoTitleBar ?
7536 {
7537 IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);
7539 }
7540}
7541
7542// [EXPERIMENTAL] Called by Begin(). NextWindowData is valid at this point.
7543// This is designed as a toy/test-bed for
7545{
7546 ImGuiContext& g = *GImGui;
7547 window->SkipRefresh = false;
7549 return;
7551 {
7552 // FIXME-IDLE: Tests for e.g. mouse clicks or keyboard while focused.
7553 if (window->Appearing) // If currently appearing
7554 return;
7555 if (window->Hidden) // If was hidden (previous frame)
7556 return;
7559 return;
7562 return;
7563 window->DrawList = NULL;
7564 window->SkipRefresh = true;
7565 }
7566}
7567
7569{
7570 window->Active = true;
7571 for (ImGuiWindow* child : window->DC.ChildWindows)
7572 if (!child->Hidden)
7573 {
7574 child->Active = child->SkipRefresh = true;
7576 }
7577}
7578
7579// Push a new Dear ImGui window to add widgets to.
7580// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.
7581// - Begin/End can be called multiple times during the frame with the same window name to append content.
7582// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
7583// You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file.
7584// - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned.
7585// - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed.
7586bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
7587{
7588 ImGuiContext& g = *GImGui;
7589 const ImGuiStyle& style = g.Style;
7590 IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required
7591 IM_ASSERT(g.WithinFrameScope); // Forgot to call ImGui::NewFrame()
7592 IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
7593
7594 // Find or create
7595 ImGuiWindow* window = FindWindowByName(name);
7596 const bool window_just_created = (window == NULL);
7597 if (window_just_created)
7598 window = CreateNewWindow(name, flags);
7599
7600 // [DEBUG] Debug break requested by user
7601 if (g.DebugBreakInWindow == window->ID)
7603
7604 // Automatically disable manual moving/resizing when NoInputs is set
7607
7608 const int current_frame = g.FrameCount;
7609 const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
7611
7612 // Update the Appearing flag (note: the BeginDocked() path may also set this to true later)
7613 bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
7614 if (flags & ImGuiWindowFlags_Popup)
7615 {
7617 window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
7618 window_just_activated_by_user |= (window != popup_ref.Window);
7619 }
7620
7621 // Update Flags, LastFrameActive, BeginOrderXXX fields
7622 const bool window_was_appearing = window->Appearing;
7623 if (first_begin_of_the_frame)
7624 {
7625 UpdateWindowInFocusOrderList(window, window_just_created, flags);
7626 window->Appearing = window_just_activated_by_user;
7627 if (window->Appearing)
7629 window->FlagsPreviousFrame = window->Flags;
7630 window->Flags = (ImGuiWindowFlags)flags;
7632 window->LastFrameActive = current_frame;
7633 window->LastTimeActive = (float)g.Time;
7634 window->BeginOrderWithinParent = 0;
7635 window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);
7636 }
7637 else
7638 {
7639 flags = window->Flags;
7640 }
7641
7642 // Docking
7643 // (NB: during the frame dock nodes are created, it is possible that (window->DockIsActive == false) even though (window->DockNode->Windows.Size > 1)
7644 IM_ASSERT(window->DockNode == NULL || window->DockNodeAsHost == NULL); // Cannot be both
7647 if (first_begin_of_the_frame)
7648 {
7649 bool has_dock_node = (window->DockId != 0 || window->DockNode != NULL);
7650 bool new_auto_dock_node = !has_dock_node && GetWindowAlwaysWantOwnTabBar(window);
7651 bool dock_node_was_visible = window->DockNodeIsVisible;
7652 bool dock_tab_was_visible = window->DockTabIsVisible;
7653 if (has_dock_node || new_auto_dock_node)
7654 {
7655 BeginDocked(window, p_open);
7656 flags = window->Flags;
7657 if (window->DockIsActive)
7658 {
7659 IM_ASSERT(window->DockNode != NULL);
7660 g.NextWindowData.HasFlags &= ~ImGuiNextWindowDataFlags_HasSizeConstraint; // Docking currently override constraints
7661 }
7662
7663 // Amend the Appearing flag
7664 if (window->DockTabIsVisible && !dock_tab_was_visible && dock_node_was_visible && !window->Appearing && !window_was_appearing)
7665 {
7666 window->Appearing = true;
7668 }
7669 }
7670 else
7671 {
7672 window->DockIsActive = window->DockNodeIsVisible = window->DockTabIsVisible = false;
7673 }
7674 }
7675
7676 // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack
7677 ImGuiWindow* parent_window_in_stack = (window->DockIsActive && window->DockNode->HostWindow) ? window->DockNode->HostWindow : g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window;
7678 ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
7679 IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
7680
7681 // We allow window memory to be compacted so recreate the base stack when needed.
7682 if (window->IDStack.Size == 0)
7683 window->IDStack.push_back(window->ID);
7684
7685 // Add to stack
7686 g.CurrentWindow = window;
7688 ImGuiWindowStackData& window_stack_data = g.CurrentWindowStack.back();
7689 window_stack_data.Window = window;
7690 window_stack_data.ParentLastItemDataBackup = g.LastItemData;
7692 window_stack_data.DisabledOverrideReenableAlphaBackup = 0.0f;
7693 ErrorRecoveryStoreState(&window_stack_data.StackSizesInBegin);
7695 if (flags & ImGuiWindowFlags_ChildMenu)
7696 g.BeginMenuDepth++;
7697
7698 // Update ->RootWindow and others pointers (before any possible call to FocusWindow)
7699 if (first_begin_of_the_frame)
7700 {
7701 UpdateWindowParentAndRootLinks(window, flags, parent_window);
7702 window->ParentWindowInBeginStack = parent_window_in_stack;
7703
7704 // Focus route
7705 // There's little point to expose a flag to set this: because the interesting cases won't be using parent_window_in_stack,
7706 // Use for e.g. linking a tool window in a standalone viewport to a document window, regardless of their Begin() stack parenting. (#6798)
7707 window->ParentWindowForFocusRoute = (window->RootWindow != window) ? parent_window_in_stack : NULL;
7708 if (window->ParentWindowForFocusRoute == NULL && window->DockNode != NULL)
7711
7712 // Override with SetNextWindowClass() field or direct call to SetWindowParentWindowForFocusRoute()
7713 if (window->WindowClass.FocusRouteParentWindowId != 0)
7714 {
7716 IM_ASSERT(window->ParentWindowForFocusRoute != 0); // Invalid value for FocusRouteParentWindowId.
7717 }
7718
7719 // Inherit SetWindowFontScale() from parent until we fix this system...
7720 window->FontWindowScaleParents = parent_window ? parent_window->FontWindowScaleParents * parent_window->FontWindowScale : 1.0f;
7721 }
7722
7723 // Add to focus scope stack
7726
7727 // Add to popup stacks: update OpenPopupStack[] data, push to BeginPopupStack[]
7728 if (flags & ImGuiWindowFlags_Popup)
7729 {
7731 popup_ref.Window = window;
7732 popup_ref.ParentNavLayer = parent_window_in_stack->DC.NavLayerCurrent;
7733 g.BeginPopupStack.push_back(popup_ref);
7734 window->PopupId = popup_ref.PopupId;
7735 }
7736
7737 // Process SetNextWindow***() calls
7738 // (FIXME: Consider splitting the HasXXX flags into X/Y components
7739 bool window_pos_set_by_api = false;
7740 bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
7742 {
7743 window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
7744 if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
7745 {
7746 // May be processed on the next frame if this is our first frame and we are measuring size
7747 // FIXME: Look into removing the branch so everything can go through this same code path for consistency.
7751 }
7752 else
7753 {
7755 }
7756 }
7758 {
7759 window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
7760 window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
7761 if ((window->ChildFlags & ImGuiChildFlags_ResizeX) && (window->SetWindowSizeAllowFlags & ImGuiCond_FirstUseEver) == 0) // Axis-specific conditions for BeginChild()
7762 g.NextWindowData.SizeVal.x = window->SizeFull.x;
7764 g.NextWindowData.SizeVal.y = window->SizeFull.y;
7766 }
7768 {
7769 if (g.NextWindowData.ScrollVal.x >= 0.0f)
7770 {
7772 window->ScrollTargetCenterRatio.x = 0.0f;
7773 }
7774 if (g.NextWindowData.ScrollVal.y >= 0.0f)
7775 {
7777 window->ScrollTargetCenterRatio.y = 0.0f;
7778 }
7779 }
7782 else if (first_begin_of_the_frame)
7783 window->ContentSizeExplicit = ImVec2(0.0f, 0.0f);
7789 FocusWindow(window);
7790 if (window->Appearing)
7792
7793 // [EXPERIMENTAL] Skip Refresh mode
7795
7796 // Nested root windows (typically tooltips) override disabled state
7797 if (window_stack_data.DisabledOverrideReenable && window->RootWindow == window)
7799
7800 // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
7801 g.CurrentWindow = NULL;
7802
7803 // When reusing window again multiple times a frame, just append content (don't need to setup again)
7804 if (first_begin_of_the_frame && !window->SkipRefresh)
7805 {
7806 // Initialize
7807 const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
7808 const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
7809 window->Active = true;
7810 window->HasCloseButton = (p_open != NULL);
7811 window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX);
7812 window->IDStack.resize(1);
7813 window->DrawList->_ResetForNewFrame();
7814 window->DC.CurrentTableIdx = -1;
7816 {
7817 window->DrawList->ChannelsSplit(2);
7818 window->DrawList->ChannelsSetCurrent(DOCKING_HOST_DRAW_CHANNEL_FG); // Render decorations on channel 1 as we will render the backgrounds manually later
7819 }
7820
7821 // Restore buffer capacity when woken from a compacted state, to avoid
7822 if (window->MemoryCompacted)
7824
7825 // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged).
7826 // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere.
7827 bool window_title_visible_elsewhere = false;
7828 if ((window->Viewport && window->Viewport->Window == window) || (window->DockIsActive))
7829 window_title_visible_elsewhere = true;
7830 else if (g.NavWindowingListWindow != NULL && (flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB
7831 window_title_visible_elsewhere = true;
7832 else if (flags & ImGuiWindowFlags_ChildMenu)
7833 window_title_visible_elsewhere = true;
7834 if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0)
7835 {
7836 size_t buf_len = (size_t)window->NameBufLen;
7837 window->Name = ImStrdupcpy(window->Name, &buf_len, name);
7838 window->NameBufLen = (int)buf_len;
7839 }
7840
7841 // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
7842
7843 // Update contents size from last frame for auto-fitting (or use explicit size)
7844 CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal);
7845
7846 // FIXME: These flags are decremented before they are used. This means that in order to have these fields produce their intended behaviors
7847 // for one frame we must set them to at least 2, which is counter-intuitive. HiddenFramesCannotSkipItems is a more complicated case because
7848 // it has a single usage before this code block and may be set below before it is finally checked.
7849 if (window->HiddenFramesCanSkipItems > 0)
7850 window->HiddenFramesCanSkipItems--;
7851 if (window->HiddenFramesCannotSkipItems > 0)
7853 if (window->HiddenFramesForRenderOnly > 0)
7854 window->HiddenFramesForRenderOnly--;
7855
7856 // Hide new windows for one frame until they calculate their size
7857 if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))
7858 window->HiddenFramesCannotSkipItems = 1;
7859
7860 // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
7861 // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
7862 if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
7863 {
7864 window->HiddenFramesCannotSkipItems = 1;
7866 {
7867 if (!window_size_x_set_by_api)
7868 window->Size.x = window->SizeFull.x = 0.f;
7869 if (!window_size_y_set_by_api)
7870 window->Size.y = window->SizeFull.y = 0.f;
7871 window->ContentSize = window->ContentSizeIdeal = ImVec2(0.f, 0.f);
7872 }
7873 }
7874
7875 // SELECT VIEWPORT
7876 // We need to do this before using any style/font sizes, as viewport with a different DPI may affect font sizes.
7877
7878 WindowSelectViewport(window);
7879 SetCurrentViewport(window, window->Viewport);
7880 SetCurrentWindow(window);
7881 flags = window->Flags;
7882
7883 // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies)
7884 // We read Style data after the call to UpdateSelectWindowViewport() which might be swapping the style.
7885
7886 if (!window->DockIsActive && (flags & ImGuiWindowFlags_ChildWindow))
7887 window->WindowBorderSize = style.ChildBorderSize;
7888 else
7890 window->WindowPadding = style.WindowPadding;
7891 if (!window->DockIsActive && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !(window->ChildFlags & ImGuiChildFlags_AlwaysUseWindowPadding) && window->WindowBorderSize == 0.0f)
7892 window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);
7893
7894 // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size.
7897 window->TitleBarHeight = (flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : g.FontSize + g.Style.FramePadding.y * 2.0f;
7898 window->MenuBarHeight = (flags & ImGuiWindowFlags_MenuBar) ? window->DC.MenuBarOffset.y + g.FontSize + g.Style.FramePadding.y * 2.0f : 0.0f;
7899 window->FontRefSize = g.FontSize; // Lock this to discourage calling window->CalcFontSize() outside of current window.
7900
7901 // Depending on condition we use previous or current window size to compare against contents size to decide if a scrollbar should be visible.
7902 // Those flags will be altered further down in the function depending on more conditions.
7903 bool use_current_size_for_scrollbar_x = window_just_created;
7904 bool use_current_size_for_scrollbar_y = window_just_created;
7905 if (window_size_x_set_by_api && window->ContentSizeExplicit.x != 0.0f)
7906 use_current_size_for_scrollbar_x = true;
7907 if (window_size_y_set_by_api && window->ContentSizeExplicit.y != 0.0f) // #7252
7908 use_current_size_for_scrollbar_y = true;
7909
7910 // Collapse window by double-clicking on title bar
7911 // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing
7912 if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse) && !window->DockIsActive)
7913 {
7914 // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed),
7915 // so verify that we don't have items over the title bar.
7916 ImRect title_bar_rect = window->TitleBarRect();
7917 if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && g.ActiveId == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max))
7919 window->WantCollapseToggle = true;
7920 if (window->WantCollapseToggle)
7921 {
7922 window->Collapsed = !window->Collapsed;
7923 if (!window->Collapsed)
7924 use_current_size_for_scrollbar_y = true;
7925 MarkIniSettingsDirty(window);
7926 }
7927 }
7928 else
7929 {
7930 window->Collapsed = false;
7931 }
7932 window->WantCollapseToggle = false;
7933
7934 // SIZE
7935
7936 // Outer Decoration Sizes
7937 // (we need to clear ScrollbarSize immediately as CalcWindowAutoFitSize() needs it and can be called from other locations).
7938 const ImVec2 scrollbar_sizes_from_last_frame = window->ScrollbarSizes;
7939 window->DecoOuterSizeX1 = 0.0f;
7940 window->DecoOuterSizeX2 = 0.0f;
7941 window->DecoOuterSizeY1 = window->TitleBarHeight + window->MenuBarHeight;
7942 window->DecoOuterSizeY2 = 0.0f;
7943 window->ScrollbarSizes = ImVec2(0.0f, 0.0f);
7944
7945 // Calculate auto-fit size, handle automatic resize
7946 const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal);
7947 if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
7948 {
7949 // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
7950 if (!window_size_x_set_by_api)
7951 {
7952 window->SizeFull.x = size_auto_fit.x;
7953 use_current_size_for_scrollbar_x = true;
7954 }
7955 if (!window_size_y_set_by_api)
7956 {
7957 window->SizeFull.y = size_auto_fit.y;
7958 use_current_size_for_scrollbar_y = true;
7959 }
7960 }
7961 else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
7962 {
7963 // Auto-fit may only grow window during the first few frames
7964 // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
7965 if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
7966 {
7967 window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
7968 use_current_size_for_scrollbar_x = true;
7969 }
7970 if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
7971 {
7972 window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
7973 use_current_size_for_scrollbar_y = true;
7974 }
7975 if (!window->Collapsed)
7976 MarkIniSettingsDirty(window);
7977 }
7978
7979 // Apply minimum/maximum window size constraints and final size
7980 window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull);
7981 window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
7982
7983 // POSITION
7984
7985 // Popup latch its initial position, will position itself when it appears next frame
7986 if (window_just_activated_by_user)
7987 {
7989 if ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api) // FIXME: BeginPopup() could use SetNextWindowPos()
7990 window->Pos = g.BeginPopupStack.back().OpenPopupPos;
7991 }
7992
7993 // Position child window
7994 if (flags & ImGuiWindowFlags_ChildWindow)
7995 {
7996 IM_ASSERT(parent_window && parent_window->Active);
7997 window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size;
7998 parent_window->DC.ChildWindows.push_back(window);
7999 if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
8000 window->Pos = parent_window->DC.CursorPos;
8001 }
8002
8003 const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0);
8004 if (window_pos_with_pivot)
8005 SetWindowPos(window, window->SetWindowPosVal - window->Size * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering)
8006 else if ((flags & ImGuiWindowFlags_ChildMenu) != 0)
8007 window->Pos = FindBestWindowPosForPopup(window);
8008 else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
8009 window->Pos = FindBestWindowPosForPopup(window);
8010 else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
8011 window->Pos = FindBestWindowPosForPopup(window);
8012
8013 // Late create viewport if we don't fit within our current host viewport.
8015 if (!window->Viewport->GetMainRect().Contains(window->Rect()))
8016 {
8017 // This is based on the assumption that the DPI will be known ahead (same as the DPI of the selection done in UpdateSelectWindowViewport)
8018 //ImGuiViewport* old_viewport = window->Viewport;
8019 window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_NoFocusOnAppearing);
8020
8021 // FIXME-DPI
8022 //IM_ASSERT(old_viewport->DpiScale == window->Viewport->DpiScale); // FIXME-DPI: Something went wrong
8023 SetCurrentViewport(window, window->Viewport);
8024 SetCurrentWindow(window);
8025 }
8026
8027 if (window->ViewportOwned)
8028 WindowSyncOwnedViewport(window, parent_window_in_stack);
8029
8030 // Calculate the range of allowed position for that window (to be movable and visible past safe area padding)
8031 // When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect.
8032 ImRect viewport_rect(window->Viewport->GetMainRect());
8033 ImRect viewport_work_rect(window->Viewport->GetWorkRect());
8034 ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
8035 ImRect visibility_rect(viewport_work_rect.Min + visibility_padding, viewport_work_rect.Max - visibility_padding);
8036
8037 // Clamp position/size so window stays visible within its viewport or monitor
8038 // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
8039 // FIXME: Similar to code in GetWindowAllowedExtentRect()
8040 if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow))
8041 {
8042 if (!window->ViewportOwned && viewport_rect.GetWidth() > 0 && viewport_rect.GetHeight() > 0.0f)
8043 {
8044 ClampWindowPos(window, visibility_rect);
8045 }
8046 else if (window->ViewportOwned && g.PlatformIO.Monitors.Size > 0)
8047 {
8048 if (g.MovingWindow != NULL && window->RootWindowDockTree == g.MovingWindow->RootWindowDockTree)
8049 {
8050 // While moving windows we allow them to straddle monitors (#7299, #3071)
8051 visibility_rect = g.PlatformMonitorsFullWorkRect;
8052 }
8053 else
8054 {
8055 // When not moving ensure visible in its monitor
8056 // Lost windows (e.g. a monitor disconnected) will naturally moved to the fallback/dummy monitor aka the main viewport.
8058 visibility_rect = ImRect(monitor->WorkPos, monitor->WorkPos + monitor->WorkSize);
8059 }
8060 visibility_rect.Expand(-visibility_padding);
8061 ClampWindowPos(window, visibility_rect);
8062 }
8063 }
8064 window->Pos = ImTrunc(window->Pos);
8065
8066 // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
8067 // Large values tend to lead to variety of artifacts and are not recommended.
8068 if (window->ViewportOwned || window->DockIsActive)
8069 window->WindowRounding = 0.0f;
8070 else
8071 window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
8072
8073 // For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts.
8074 //if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar))
8075 // window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f);
8076
8077 // Apply window focus (new and reactivated windows are moved to front)
8078 bool want_focus = false;
8079 if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
8080 {
8081 if (flags & ImGuiWindowFlags_Popup)
8082 want_focus = true;
8083 else if ((window->DockIsActive || (flags & ImGuiWindowFlags_ChildWindow) == 0) && !(flags & ImGuiWindowFlags_Tooltip))
8084 want_focus = true;
8085 }
8086
8087 // [Test Engine] Register whole window in the item system (before submitting further decorations)
8088#ifdef IMGUI_ENABLE_TEST_ENGINE
8089 if (g.TestEngineHookItems)
8090 {
8091 IM_ASSERT(window->IDStack.Size == 1);
8092 window->IDStack.Size = 0; // As window->IDStack[0] == window->ID here, make sure TestEngine doesn't erroneously see window as parent of itself.
8094 IMGUI_TEST_ENGINE_ITEM_ADD(window->ID, window->Rect(), NULL);
8096 window->IDStack.Size = 1;
8098
8099 }
8100#endif
8101
8102 // Decide if we are going to handle borders and resize grips
8103 const bool handle_borders_and_resize_grips = (window->DockNodeAsHost || !window->DockIsActive);
8104
8105 // Handle manual resize: Resize Grips, Borders, Gamepad
8106 int border_hovered = -1, border_held = -1;
8107 ImU32 resize_grip_col[4] = {};
8108 const int resize_grip_count = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup)) ? 0 : g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
8109 const float resize_grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
8110 if (handle_borders_and_resize_grips && !window->Collapsed)
8111 if (int auto_fit_mask = UpdateWindowManualResize(window, size_auto_fit, &border_hovered, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect))
8112 {
8113 if (auto_fit_mask & (1 << ImGuiAxis_X))
8114 use_current_size_for_scrollbar_x = true;
8115 if (auto_fit_mask & (1 << ImGuiAxis_Y))
8116 use_current_size_for_scrollbar_y = true;
8117 }
8118 window->ResizeBorderHovered = (signed char)border_hovered;
8119 window->ResizeBorderHeld = (signed char)border_held;
8120
8121 // Synchronize window --> viewport again and one last time (clamping and manual resize may have affected either)
8122 if (window->ViewportOwned)
8123 {
8124 if (!window->Viewport->PlatformRequestMove)
8125 window->Viewport->Pos = window->Pos;
8126 if (!window->Viewport->PlatformRequestResize)
8127 window->Viewport->Size = window->Size;
8128 window->Viewport->UpdateWorkRect();
8129 viewport_rect = window->Viewport->GetMainRect();
8130 }
8131
8132 // Save last known viewport position within the window itself (so it can be saved in .ini file and restored)
8133 window->ViewportPos = window->Viewport->Pos;
8134
8135 // SCROLLBAR VISIBILITY
8136
8137 // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size).
8138 if (!window->Collapsed)
8139 {
8140 // When reading the current size we need to read it after size constraints have been applied.
8141 // Intentionally use previous frame values for InnerRect and ScrollbarSizes.
8142 // And when we use window->DecorationUp here it doesn't have ScrollbarSizes.y applied yet.
8143 ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2));
8144 ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + scrollbar_sizes_from_last_frame;
8145 ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;
8146 float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
8147 float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
8148 bool scrollbar_x_prev = window->ScrollbarX;
8149 //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons?
8150 window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
8151 window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
8152
8153 // Track when ScrollbarX visibility keeps toggling, which is a sign of a feedback loop, and stabilize by enforcing visibility (#3285, #8488)
8154 // (Feedback loops of this sort can manifest in various situations, but combining horizontal + vertical scrollbar + using a clipper with varying width items is one frequent cause.
8155 // The better solution is to, either (1) enforce visibility by using ImGuiWindowFlags_AlwaysHorizontalScrollbar or (2) declare stable contents width with SetNextWindowContentSize(), if you can compute it)
8157 window->ScrollbarXStabilizeToggledHistory |= (scrollbar_x_prev != window->ScrollbarX) ? 0x01 : 0x00;
8158 const bool scrollbar_x_stabilize = (window->ScrollbarXStabilizeToggledHistory != 0) && ImCountSetBits(window->ScrollbarXStabilizeToggledHistory) >= 4; // 4 == half of bits in our U8 history.
8159 if (scrollbar_x_stabilize)
8160 window->ScrollbarX = true;
8161 //if (scrollbar_x_stabilize && !window->ScrollbarXStabilizeEnabled)
8162 // IMGUI_DEBUG_LOG("[scroll] Stabilize ScrollbarX for Window '%s'\n", window->Name);
8163 window->ScrollbarXStabilizeEnabled = scrollbar_x_stabilize;
8164
8165 if (window->ScrollbarX && !window->ScrollbarY)
8166 window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
8167 window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
8168
8169 // Amend the partially filled window->DecorationXXX values.
8170 window->DecoOuterSizeX2 += window->ScrollbarSizes.x;
8171 window->DecoOuterSizeY2 += window->ScrollbarSizes.y;
8172 }
8173
8174 // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING)
8175 // Update various regions. Variables they depend on should be set above in this function.
8176 // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame.
8177
8178 // Outer rectangle
8179 // Not affected by window border size. Used by:
8180 // - FindHoveredWindow() (w/ extra padding when border resize is enabled)
8181 // - Begin() initial clipping rect for drawing window background and borders.
8182 // - Begin() clipping whole child
8183 const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect;
8184 const ImRect outer_rect = window->Rect();
8185 const ImRect title_bar_rect = window->TitleBarRect();
8186 window->OuterRectClipped = outer_rect;
8187 if (window->DockIsActive)
8188 window->OuterRectClipped.Min.y += window->TitleBarHeight;
8189 window->OuterRectClipped.ClipWith(host_rect);
8190
8191 // Inner rectangle
8192 // Not affected by window border size. Used by:
8193 // - InnerClipRect
8194 // - ScrollToRectEx()
8195 // - NavUpdatePageUpPageDown()
8196 // - Scrollbar()
8197 window->InnerRect.Min.x = window->Pos.x + window->DecoOuterSizeX1;
8198 window->InnerRect.Min.y = window->Pos.y + window->DecoOuterSizeY1;
8199 window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->DecoOuterSizeX2;
8200 window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->DecoOuterSizeY2;
8201
8202 // Inner clipping rectangle.
8203 // - Extend a outside of normal work region up to borders.
8204 // - This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space.
8205 // - It also makes clipped items be more noticeable.
8206 // - And is consistent on both axis (prior to 2024/05/03 ClipRect used WindowPadding.x * 0.5f on left and right edge), see #3312
8207 // - Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
8208 // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
8209 // Affected by window/frame border size. Used by:
8210 // - Begin() initial clip rect
8211 float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
8212
8213 // Try to match the fact that our border is drawn centered over the window rectangle, rather than inner.
8214 // This is why we do a *0.5f here. We don't currently even technically support large values for WindowBorderSize,
8215 // see e.g #7887 #7888, but may do after we move the window border to become an inner border (and then we can remove the 0.5f here).
8216 window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + window->WindowBorderSize * 0.5f);
8217 window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size * 0.5f);
8218 window->InnerClipRect.Max.x = ImFloor(window->InnerRect.Max.x - window->WindowBorderSize * 0.5f);
8219 window->InnerClipRect.Max.y = ImFloor(window->InnerRect.Max.y - window->WindowBorderSize * 0.5f);
8220 window->InnerClipRect.ClipWithFull(host_rect);
8221
8222 // SCROLLING
8223
8224 // Lock down maximum scrolling
8225 // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate
8226 // for right/bottom aligned items without creating a scrollbar.
8227 window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth());
8228 window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight());
8229
8230 // Apply scrolling
8232 window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
8233 window->DecoInnerSizeX1 = window->DecoInnerSizeY1 = 0.0f;
8234
8235 // DRAWING
8236
8237 // Setup draw list and outer clipping rectangle
8238 IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0);
8240 PushClipRect(host_rect.Min, host_rect.Max, false);
8241
8242 // Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71)
8243 // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.
8244 // FIXME: User code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected (github #4493)
8245 const bool is_undocked_or_docked_visible = !window->DockIsActive || window->DockTabIsVisible;
8246 if (is_undocked_or_docked_visible)
8247 {
8248 bool render_decorations_in_parent = false;
8249 if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
8250 {
8251 // - We test overlap with the previous child window only (testing all would end up being O(log N) not a good investment here)
8252 // - We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping childs
8253 ImGuiWindow* previous_child = parent_window->DC.ChildWindows.Size >= 2 ? parent_window->DC.ChildWindows[parent_window->DC.ChildWindows.Size - 2] : NULL;
8254 bool previous_child_overlapping = previous_child ? previous_child->Rect().Overlaps(window->Rect()) : false;
8255 bool parent_is_empty = (parent_window->DrawList->VtxBuffer.Size == 0);
8256 if (window->DrawList->CmdBuffer.back().ElemCount == 0 && !parent_is_empty && !previous_child_overlapping)
8257 render_decorations_in_parent = true;
8258 }
8259 if (render_decorations_in_parent)
8260 window->DrawList = parent_window->DrawList;
8261
8262 // Handle title bar, scrollbar, resize grips and resize borders
8263 const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
8264 const bool title_bar_is_highlight = want_focus || (window_to_highlight && (window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight || (window->DockNode && window->DockNode == window_to_highlight->DockNode)));
8265 RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_count, resize_grip_col, resize_grip_draw_size);
8266
8267 if (render_decorations_in_parent)
8268 window->DrawList = &window->DrawListInst;
8269 }
8270
8271 // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING)
8272
8273 // Work rectangle.
8274 // Affected by window padding and border size. Used by:
8275 // - Columns() for right-most edge
8276 // - TreeNode(), CollapsingHeader() for right-most edge
8277 // - BeginTabBar() for right-most edge
8278 const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar);
8279 const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar);
8280 const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2)));
8281 const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2)));
8282 window->WorkRect.Min.x = ImTrunc(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize));
8283 window->WorkRect.Min.y = ImTrunc(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize));
8284 window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x;
8285 window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y;
8286 window->ParentWorkRect = window->WorkRect;
8287
8288 // [LEGACY] Content Region
8289 // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
8290 // Unless explicit content size is specified by user, this currently represent the region leading to no scrolling.
8291 // Used by:
8292 // - Mouse wheel scrolling + many other things
8293 window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x + window->DecoOuterSizeX1;
8294 window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->DecoOuterSizeY1;
8295 window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2)));
8296 window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2)));
8297
8298 // Setup drawing context
8299 // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.)
8300 window->DC.Indent.x = window->DecoOuterSizeX1 + window->WindowPadding.x - window->Scroll.x;
8301 window->DC.GroupOffset.x = 0.0f;
8302 window->DC.ColumnsOffset.x = 0.0f;
8303
8304 // Record the loss of precision of CursorStartPos which can happen due to really large scrolling amount.
8305 // This is used by clipper to compensate and fix the most common use case of large scroll area. Easy and cheap, next best thing compared to switching everything to double or ImU64.
8306 double start_pos_highp_x = (double)window->Pos.x + window->WindowPadding.x - (double)window->Scroll.x + window->DecoOuterSizeX1 + window->DC.ColumnsOffset.x;
8307 double start_pos_highp_y = (double)window->Pos.y + window->WindowPadding.y - (double)window->Scroll.y + window->DecoOuterSizeY1;
8308 window->DC.CursorStartPos = ImVec2((float)start_pos_highp_x, (float)start_pos_highp_y);
8309 window->DC.CursorStartPosLossyness = ImVec2((float)(start_pos_highp_x - window->DC.CursorStartPos.x), (float)(start_pos_highp_y - window->DC.CursorStartPos.y));
8310 window->DC.CursorPos = window->DC.CursorStartPos;
8311 window->DC.CursorPosPrevLine = window->DC.CursorPos;
8312 window->DC.CursorMaxPos = window->DC.CursorStartPos;
8313 window->DC.IdealMaxPos = window->DC.CursorStartPos;
8314 window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
8315 window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
8316 window->DC.IsSameLine = window->DC.IsSetPos = false;
8317
8320 window->DC.NavLayersActiveMaskNext = 0x00;
8321 window->DC.NavIsScrollPushableX = true;
8322 window->DC.NavHideHighlightOneFrame = false;
8323 window->DC.NavWindowHasScrollY = (window->ScrollMax.y > 0.0f);
8324
8325 window->DC.MenuBarAppending = false;
8326 window->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user);
8327 window->DC.TreeDepth = 0;
8329 window->DC.ChildWindows.resize(0);
8330 window->DC.StateStorage = &window->StateStorage;
8331 window->DC.CurrentColumns = NULL;
8333 window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
8334
8335 // Default item width. Make it proportional to window size if window manually resizes
8336 if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
8337 window->ItemWidthDefault = ImTrunc(window->Size.x * 0.65f);
8338 else
8339 window->ItemWidthDefault = ImTrunc(g.FontSize * 16.0f);
8340 window->DC.ItemWidth = window->ItemWidthDefault;
8341 window->DC.TextWrapPos = -1.0f; // disabled
8342 window->DC.ItemWidthStack.resize(0);
8343 window->DC.TextWrapPosStack.resize(0);
8344 if (flags & ImGuiWindowFlags_Modal)
8346
8347 if (window->AutoFitFramesX > 0)
8348 window->AutoFitFramesX--;
8349 if (window->AutoFitFramesY > 0)
8350 window->AutoFitFramesY--;
8351
8352 // Clear SetNextWindowXXX data (can aim to move this higher in the function)
8354
8355 // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
8356 // We ImGuiFocusRequestFlags_UnlessBelowModal to:
8357 // - Avoid focusing a window that is created outside of a modal. This will prevent active modal from being closed.
8358 // - Position window behind the modal that is not a begin-parent of this window.
8359 if (want_focus)
8361 if (want_focus && window == g.NavWindow)
8362 NavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls
8363
8364 // Close requested by platform window (apply to all windows in this viewport)
8365 if (p_open != NULL && window->Viewport->PlatformRequestClose && window->Viewport != GetMainViewport())
8366 {
8367 IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Window '%s' closed by PlatformRequestClose\n", window->Name);
8368 *p_open = false;
8369 g.NavWindowingToggleLayer = false; // Assume user mapped PlatformRequestClose on ALT-F4 so we disable ALT for menu toggle. False positive not an issue. // FIXME-NAV: Try removing.
8370 }
8371
8372 // Pressing CTRL+C copy window content into the clipboard
8373 // [EXPERIMENTAL] Breaks on nested Begin/End pairs. We need to work that out and add better logging scope.
8374 // [EXPERIMENTAL] Text outputs has many issues.
8376 if (g.NavWindow && g.NavWindow->RootWindow == window && g.ActiveId == 0 && Shortcut(ImGuiMod_Ctrl | ImGuiKey_C))
8377 LogToClipboard(0);
8378
8379 // Title bar
8380 if (!(flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive)
8381 RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), name, p_open);
8382 else if (!(flags & ImGuiWindowFlags_NoTitleBar) && window->DockIsActive)
8383 LogText("%.*s\n", (int)(FindRenderedTextEnd(window->Name) - window->Name), window->Name);
8384
8385 // Clear hit test shape every frame
8386 window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0;
8387
8388 if (flags & ImGuiWindowFlags_Tooltip)
8389 g.TooltipPreviousWindow = window;
8390
8392 {
8393 // Docking: Dragging a dockable window (or any of its child) turns it into a drag and drop source.
8394 // We need to do this _before_ we overwrite window->DC.LastItemId below because BeginDockableDragDropSource() also overwrites it.
8395 if (g.MovingWindow == window && (window->RootWindowDockTree->Flags & ImGuiWindowFlags_NoDocking) == 0)
8397
8398 // Docking: Any dockable window can act as a target. For dock node hosts we call BeginDockableDragDropTarget() in DockNodeUpdate() instead.
8399 if (g.DragDropActive && !(flags & ImGuiWindowFlags_NoDocking))
8400 if (g.MovingWindow == NULL || g.MovingWindow->RootWindowDockTree != window)
8401 if ((window == window->RootWindowDockTree) && !(window->Flags & ImGuiWindowFlags_DockNodeHost))
8403 }
8404
8405 // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin().
8406 // This is useful to allow creating context menus on title bar only, etc.
8408 window->DC.WindowItemStatusFlags |= IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0;
8409 SetLastItemDataForWindow(window, title_bar_rect);
8410
8411 // [DEBUG]
8412#ifndef IMGUI_DISABLE_DEBUG_TOOLS
8413 if (g.DebugLocateId != 0 && (window->ID == g.DebugLocateId || window->MoveId == g.DebugLocateId))
8415#endif
8416
8417 // [Test Engine] Register title bar / tab with MoveId.
8418#ifdef IMGUI_ENABLE_TEST_ENGINE
8419 if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
8420 {
8424 }
8425#endif
8426 }
8427 else
8428 {
8429 // Skip refresh always mark active
8430 if (window->SkipRefresh)
8432
8433 // Append
8434 SetCurrentViewport(window, window->Viewport);
8435 SetCurrentWindow(window);
8437 SetLastItemDataForWindow(window, window->TitleBarRect());
8438 }
8439
8440 if (!(flags & ImGuiWindowFlags_DockNodeHost) && !window->SkipRefresh)
8441 PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
8442
8443 // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused)
8444 window->WriteAccessed = false;
8445 window->BeginCount++;
8446
8447 // Update visibility
8448 if (first_begin_of_the_frame && !window->SkipRefresh)
8449 {
8450 // When we are about to select this tab (which will only be visible on the _next frame_), flag it with a non-zero HiddenFramesCannotSkipItems.
8451 // This will have the important effect of actually returning true in Begin() and not setting SkipItems, allowing an earlier submission of the window contents.
8452 // This is analogous to regular windows being hidden from one frame.
8453 // It is especially important as e.g. nested TabBars would otherwise generate flicker in the form of one empty frame, or focus requests won't be processed.
8454 if (window->DockIsActive && !window->DockTabIsVisible)
8455 {
8456 if (window->LastFrameJustFocused == g.FrameCount)
8457 window->HiddenFramesCannotSkipItems = 1;
8458 else
8459 window->HiddenFramesCanSkipItems = 1;
8460 }
8461
8462 if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ChildMenu))
8463 {
8464 // Child window can be out of sight and have "negative" clip windows.
8465 // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
8466 IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0 || window->DockIsActive);
8467 const bool nav_request = (window->ChildFlags & ImGuiChildFlags_NavFlattened) && (g.NavAnyRequest && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
8468 if (!g.LogEnabled && !nav_request)
8469 if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
8470 {
8471 if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
8472 window->HiddenFramesCannotSkipItems = 1;
8473 else
8474 window->HiddenFramesCanSkipItems = 1;
8475 }
8476
8477 // Hide along with parent or if parent is collapsed
8478 if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))
8479 window->HiddenFramesCanSkipItems = 1;
8480 if (parent_window && parent_window->HiddenFramesCannotSkipItems > 0)
8481 window->HiddenFramesCannotSkipItems = 1;
8482 }
8483
8484 // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point)
8485 if (style.Alpha <= 0.0f)
8486 window->HiddenFramesCanSkipItems = 1;
8487
8488 // Update the Hidden flag
8489 bool hidden_regular = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0);
8490 window->Hidden = hidden_regular || (window->HiddenFramesForRenderOnly > 0);
8491
8492 // Disable inputs for requested number of frames
8493 if (window->DisableInputsFrames > 0)
8494 {
8495 window->DisableInputsFrames--;
8497 }
8498
8499 // Update the SkipItems flag, used to early out of all items functions (no layout required)
8500 bool skip_items = false;
8501 if (window->Collapsed || !window->Active || hidden_regular)
8502 if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)
8503 skip_items = true;
8504 window->SkipItems = skip_items;
8505
8506 // Restore NavLayersActiveMaskNext to previous value when not visible, so a CTRL+Tab back can use a safe value.
8507 if (window->SkipItems)
8509
8510 // Sanity check: there are two spots which can set Appearing = true
8511 // - when 'window_just_activated_by_user' is set -> HiddenFramesCannotSkipItems is set -> SkipItems always false
8512 // - in BeginDocked() path when DockNodeIsVisible == DockTabIsVisible == true -> hidden _should_ be all zero // FIXME: Not formally proven, hence the assert.
8513 if (window->SkipItems && !window->Appearing)
8514 IM_ASSERT(window->Appearing == false); // Please report on GitHub if this triggers: https://github.com/ocornut/imgui/issues/4177
8515 }
8516 else if (first_begin_of_the_frame)
8517 {
8518 // Skip refresh mode
8519 window->SkipItems = true;
8520 }
8521
8522 // [DEBUG] io.ConfigDebugBeginReturnValue override return value to test Begin/End and BeginChild/EndChild behaviors.
8523 // (The implicit fallback window is NOT automatically ended allowing it to always be able to receive commands without crashing)
8524#ifndef IMGUI_DISABLE_DEBUG_TOOLS
8525 if (!window->IsFallbackWindow)
8527 {
8528 if (window->AutoFitFramesX > 0) { window->AutoFitFramesX++; }
8529 if (window->AutoFitFramesY > 0) { window->AutoFitFramesY++; }
8530 return false;
8531 }
8532#endif
8533
8534 return !window->SkipItems;
8535}
8536
8538{
8539 ImGuiContext& g = *GImGui;
8540 ImGuiWindow* window = g.CurrentWindow;
8541
8542 // Error checking: verify that user hasn't called End() too many times!
8544 {
8545 IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!");
8546 return;
8547 }
8548 ImGuiWindowStackData& window_stack_data = g.CurrentWindowStack.back();
8549
8550 // Error checking: verify that user doesn't directly call End() on a child window.
8551 if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_DockNodeHost) && !window->DockIsActive)
8552 IM_ASSERT_USER_ERROR(g.WithinEndChildID == window->ID, "Must call EndChild() and not End()!");
8553
8554 // Close anything that is open
8555 if (window->DC.CurrentColumns)
8556 EndColumns();
8557 if (!(window->Flags & ImGuiWindowFlags_DockNodeHost) && !window->SkipRefresh) // Pop inner window clip rectangle
8558 PopClipRect();
8559 PopFocusScope();
8560 if (window_stack_data.DisabledOverrideReenable && window->RootWindow == window)
8562
8563 if (window->SkipRefresh)
8564 {
8565 IM_ASSERT(window->DrawList == NULL);
8566 window->DrawList = &window->DrawListInst;
8567 }
8568
8569 // Stop logging
8570 if (g.LogWindow == window) // FIXME: add more options for scope of logging
8571 LogFinish();
8572
8573 if (window->DC.IsSetPos)
8575
8576 // Docking: report contents sizes to parent to allow for auto-resize
8577 if (window->DockNode && window->DockTabIsVisible)
8578 if (ImGuiWindow* host_window = window->DockNode->HostWindow) // FIXME-DOCK
8579 host_window->DC.CursorMaxPos = window->DC.CursorMaxPos + window->WindowPadding - host_window->WindowPadding;
8580
8581 // Pop from window stack
8582 g.LastItemData = window_stack_data.ParentLastItemDataBackup;
8583 if (window->Flags & ImGuiWindowFlags_ChildMenu)
8584 g.BeginMenuDepth--;
8585 if (window->Flags & ImGuiWindowFlags_Popup)
8587
8588 // Error handling, state recovery
8589 if (g.IO.ConfigErrorRecovery)
8591
8594 if (g.CurrentWindow)
8596}
8597
8598void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
8599{
8600 ImGuiContext& g = *GImGui;
8601 ImGuiItemFlags item_flags = g.CurrentItemFlags;
8602 IM_ASSERT(item_flags == g.ItemFlagsStack.back());
8603 if (enabled)
8604 item_flags |= option;
8605 else
8606 item_flags &= ~option;
8607 g.CurrentItemFlags = item_flags;
8608 g.ItemFlagsStack.push_back(item_flags);
8609}
8610
8612{
8613 ImGuiContext& g = *GImGui;
8614 if (g.ItemFlagsStack.Size <= 1)
8615 {
8616 IM_ASSERT_USER_ERROR(0, "Calling PopItemFlag() too many times!");
8617 return;
8618 }
8621}
8622
8623// BeginDisabled()/EndDisabled()
8624// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled)
8625// - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently.
8626// - Feedback welcome at https://github.com/ocornut/imgui/issues/211
8627// - BeginDisabled(false)/EndDisabled() essentially does nothing but is provided to facilitate use of boolean expressions.
8628// (as a micro-optimization: if you have tens of thousands of BeginDisabled(false)/EndDisabled() pairs, you might want to reformulate your code to avoid making those calls)
8629// - Note: mixing up BeginDisabled() and PushItemFlag(ImGuiItemFlags_Disabled) is currently NOT SUPPORTED.
8630void ImGui::BeginDisabled(bool disabled)
8631{
8632 ImGuiContext& g = *GImGui;
8633 bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
8634 if (!was_disabled && disabled)
8635 {
8637 g.Style.Alpha *= g.Style.DisabledAlpha; // PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * g.Style.DisabledAlpha);
8638 }
8639 if (was_disabled || disabled)
8641 g.ItemFlagsStack.push_back(g.CurrentItemFlags); // FIXME-OPT: can we simply skip this and use DisabledStackSize?
8643}
8644
8646{
8647 ImGuiContext& g = *GImGui;
8648 if (g.DisabledStackSize <= 0)
8649 {
8650 IM_ASSERT_USER_ERROR(0, "Calling EndDisabled() too many times!");
8651 return;
8652 }
8654 bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
8655 //PopItemFlag();
8658 if (was_disabled && (g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0)
8659 g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar();
8660}
8661
8662// Could have been called BeginDisabledDisable() but it didn't want to be award nominated for most awkward function name.
8663// Ideally we would use a shared e.g. BeginDisabled()->BeginDisabledEx() but earlier needs to be optimal.
8664// The whole code for this is awkward, will reevaluate if we find a way to implement SetNextItemDisabled().
8666{
8667 ImGuiContext& g = *GImGui;
8671 g.CurrentItemFlags &= ~ImGuiItemFlags_Disabled;
8674}
8675
8677{
8678 ImGuiContext& g = *GImGui;
8684}
8685
8686void ImGui::PushTextWrapPos(float wrap_pos_x)
8687{
8688 ImGuiContext& g = *GImGui;
8689 ImGuiWindow* window = g.CurrentWindow;
8690 window->DC.TextWrapPosStack.push_back(window->DC.TextWrapPos);
8691 window->DC.TextWrapPos = wrap_pos_x;
8692}
8693
8695{
8696 ImGuiContext& g = *GImGui;
8697 ImGuiWindow* window = g.CurrentWindow;
8698 if (window->DC.TextWrapPosStack.Size <= 0)
8699 {
8700 IM_ASSERT_USER_ERROR(0, "Calling PopTextWrapPos() too many times!");
8701 return;
8702 }
8703 window->DC.TextWrapPos = window->DC.TextWrapPosStack.back();
8704 window->DC.TextWrapPosStack.pop_back();
8705}
8706
8707static ImGuiWindow* GetCombinedRootWindow(ImGuiWindow* window, bool popup_hierarchy, bool dock_hierarchy)
8708{
8709 ImGuiWindow* last_window = NULL;
8710 while (last_window != window)
8711 {
8712 last_window = window;
8713 window = window->RootWindow;
8714 if (popup_hierarchy)
8715 window = window->RootWindowPopupTree;
8716 if (dock_hierarchy)
8717 window = window->RootWindowDockTree;
8718 }
8719 return window;
8720}
8721
8722bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy, bool dock_hierarchy)
8723{
8724 ImGuiWindow* window_root = GetCombinedRootWindow(window, popup_hierarchy, dock_hierarchy);
8725 if (window_root == potential_parent)
8726 return true;
8727 while (window != NULL)
8728 {
8729 if (window == potential_parent)
8730 return true;
8731 if (window == window_root) // end of chain
8732 return false;
8733 window = window->ParentWindow;
8734 }
8735 return false;
8736}
8737
8739{
8740 if (window->RootWindow == potential_parent)
8741 return true;
8742 while (window != NULL)
8743 {
8744 if (window == potential_parent)
8745 return true;
8746 window = window->ParentWindowInBeginStack;
8747 }
8748 return false;
8749}
8750
8751bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below)
8752{
8753 ImGuiContext& g = *GImGui;
8754
8755 // It would be saner to ensure that display layer is always reflected in the g.Windows[] order, which would likely requires altering all manipulations of that array
8756 const int display_layer_delta = GetWindowDisplayLayer(potential_above) - GetWindowDisplayLayer(potential_below);
8757 if (display_layer_delta != 0)
8758 return display_layer_delta > 0;
8759
8760 for (int i = g.Windows.Size - 1; i >= 0; i--)
8761 {
8762 ImGuiWindow* candidate_window = g.Windows[i];
8763 if (candidate_window == potential_above)
8764 return true;
8765 if (candidate_window == potential_below)
8766 return false;
8767 }
8768 return false;
8769}
8770
8771// Is current window hovered and hoverable (e.g. not blocked by a popup/modal)? See ImGuiHoveredFlags_ for options.
8772// IMPORTANT: If you are trying to check whether your mouse should be dispatched to Dear ImGui or to your underlying app,
8773// you should not use this function! Use the 'io.WantCaptureMouse' boolean for that!
8774// Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" for details.
8776{
8777 ImGuiContext& g = *GImGui;
8778 IM_ASSERT_USER_ERROR((flags & ~ImGuiHoveredFlags_AllowedMaskForIsWindowHovered) == 0, "Invalid flags for IsWindowHovered()!");
8779
8780 ImGuiWindow* ref_window = g.HoveredWindow;
8781 ImGuiWindow* cur_window = g.CurrentWindow;
8782 if (ref_window == NULL)
8783 return false;
8784
8785 if ((flags & ImGuiHoveredFlags_AnyWindow) == 0)
8786 {
8787 IM_ASSERT(cur_window); // Not inside a Begin()/End()
8788 const bool popup_hierarchy = (flags & ImGuiHoveredFlags_NoPopupHierarchy) == 0;
8789 const bool dock_hierarchy = (flags & ImGuiHoveredFlags_DockHierarchy) != 0;
8790 if (flags & ImGuiHoveredFlags_RootWindow)
8791 cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy, dock_hierarchy);
8792
8793 bool result;
8795 result = IsWindowChildOf(ref_window, cur_window, popup_hierarchy, dock_hierarchy);
8796 else
8797 result = (ref_window == cur_window);
8798 if (!result)
8799 return false;
8800 }
8801
8802 if (!IsWindowContentHoverable(ref_window, flags))
8803 return false;
8805 if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != ref_window->MoveId)
8806 return false;
8807
8808 // When changing hovered window we requires a bit of stationary delay before activating hover timer.
8809 // FIXME: We don't support delay other than stationary one for now, other delay would need a way
8810 // to fulfill the possibility that multiple IsWindowHovered() with varying flag could return true
8811 // for different windows of the hierarchy. Possibly need a Hash(Current+Flags) ==> (Timer) cache.
8812 // We can implement this for _Stationary because the data is linked to HoveredWindow rather than CurrentWindow.
8813 if (flags & ImGuiHoveredFlags_ForTooltip)
8815 if ((flags & ImGuiHoveredFlags_Stationary) != 0 && g.HoverWindowUnlockedStationaryId != ref_window->ID)
8816 return false;
8817
8818 return true;
8819}
8820
8822{
8823 ImGuiContext& g = *GImGui;
8824 return g.CurrentWindow->DockId;
8825}
8826
8828{
8829 ImGuiContext& g = *GImGui;
8830 return g.CurrentWindow->DockIsActive;
8831}
8832
8834{
8835 ImGuiWindow* window = GImGui->CurrentWindow;
8836 return window->Size.x;
8837}
8838
8840{
8841 ImGuiWindow* window = GImGui->CurrentWindow;
8842 return window->Size.y;
8843}
8844
8846{
8847 ImGuiContext& g = *GImGui;
8848 ImGuiWindow* window = g.CurrentWindow;
8849 return window->Pos;
8850}
8851
8852void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
8853{
8854 // Test condition (NB: bit 0 is always true) and clear flags for next time
8855 if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
8856 return;
8857
8858 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
8860 window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
8861
8862 // Set
8863 const ImVec2 old_pos = window->Pos;
8864 window->Pos = ImTrunc(pos);
8865 ImVec2 offset = window->Pos - old_pos;
8866 if (offset.x == 0.0f && offset.y == 0.0f)
8867 return;
8868 MarkIniSettingsDirty(window);
8869 // FIXME: share code with TranslateWindow(), need to confirm whether the 3 rect modified by TranslateWindow() are desirable here.
8870 window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
8871 window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected.
8872 window->DC.IdealMaxPos += offset;
8873 window->DC.CursorStartPos += offset;
8874}
8875
8877{
8879 SetWindowPos(window, pos, cond);
8880}
8881
8882void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)
8883{
8884 if (ImGuiWindow* window = FindWindowByName(name))
8885 SetWindowPos(window, pos, cond);
8886}
8887
8889{
8891 return window->Size;
8892}
8893
8894void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
8895{
8896 // Test condition (NB: bit 0 is always true) and clear flags for next time
8897 if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
8898 return;
8899
8900 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
8902
8903 // Enable auto-fit (not done in BeginChild() path unless appearing or combined with ImGuiChildFlags_AlwaysAutoResize)
8904 if ((window->Flags & ImGuiWindowFlags_ChildWindow) == 0 || window->Appearing || (window->ChildFlags & ImGuiChildFlags_AlwaysAutoResize) != 0)
8905 window->AutoFitFramesX = (size.x <= 0.0f) ? 2 : 0;
8906 if ((window->Flags & ImGuiWindowFlags_ChildWindow) == 0 || window->Appearing || (window->ChildFlags & ImGuiChildFlags_AlwaysAutoResize) != 0)
8907 window->AutoFitFramesY = (size.y <= 0.0f) ? 2 : 0;
8908
8909 // Set
8910 ImVec2 old_size = window->SizeFull;
8911 if (size.x <= 0.0f)
8912 window->AutoFitOnlyGrows = false;
8913 else
8914 window->SizeFull.x = IM_TRUNC(size.x);
8915 if (size.y <= 0.0f)
8916 window->AutoFitOnlyGrows = false;
8917 else
8918 window->SizeFull.y = IM_TRUNC(size.y);
8919 if (old_size.x != window->SizeFull.x || old_size.y != window->SizeFull.y)
8920 MarkIniSettingsDirty(window);
8921}
8922
8924{
8925 SetWindowSize(GImGui->CurrentWindow, size, cond);
8926}
8927
8928void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)
8929{
8930 if (ImGuiWindow* window = FindWindowByName(name))
8931 SetWindowSize(window, size, cond);
8932}
8933
8934void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
8935{
8936 // Test condition (NB: bit 0 is always true) and clear flags for next time
8937 if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
8938 return;
8940
8941 // Queue applying in Begin()
8942 if (window->WantCollapseToggle)
8943 window->Collapsed ^= 1;
8944 window->WantCollapseToggle = (window->Collapsed != collapsed);
8945}
8946
8947void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size)
8948{
8949 IM_ASSERT(window->HitTestHoleSize.x == 0); // We don't support multiple holes/hit test filters
8950 window->HitTestHoleSize = ImVec2ih(size);
8951 window->HitTestHoleOffset = ImVec2ih(pos - window->Pos);
8952}
8953
8955{
8956 window->Hidden = window->SkipItems = true;
8957 window->HiddenFramesCanSkipItems = 1;
8958}
8959
8960void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)
8961{
8962 SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
8963}
8964
8966{
8968 return window->Collapsed;
8969}
8970
8972{
8974 return window->Appearing;
8975}
8976
8977void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)
8978{
8979 if (ImGuiWindow* window = FindWindowByName(name))
8980 SetWindowCollapsed(window, collapsed, cond);
8981}
8982
8983void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)
8984{
8985 ImGuiContext& g = *GImGui;
8986 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
8988 g.NextWindowData.PosVal = pos;
8989 g.NextWindowData.PosPivotVal = pivot;
8990 g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
8991 g.NextWindowData.PosUndock = true;
8992}
8993
8995{
8996 ImGuiContext& g = *GImGui;
8997 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
8999 g.NextWindowData.SizeVal = size;
9000 g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
9001}
9002
9003// For each axis:
9004// - Use 0.0f as min or FLT_MAX as max if you don't want limits, e.g. size_min = (500.0f, 0.0f), size_max = (FLT_MAX, FLT_MAX) sets a minimum width.
9005// - Use -1 for both min and max of same axis to preserve current size which itself is a constraint.
9006// - See "Demo->Examples->Constrained-resizing window" for examples.
9007void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
9008{
9009 ImGuiContext& g = *GImGui;
9011 g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
9012 g.NextWindowData.SizeCallback = custom_callback;
9013 g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
9014}
9015
9016// Content size = inner scrollable rectangle, padded with WindowPadding.
9017// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item.
9019{
9020 ImGuiContext& g = *GImGui;
9023}
9024
9026{
9027 ImGuiContext& g = *GImGui;
9029 g.NextWindowData.ScrollVal = scroll;
9030}
9031
9033{
9034 ImGuiContext& g = *GImGui;
9035 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
9037 g.NextWindowData.CollapsedVal = collapsed;
9039}
9040
9042{
9043 ImGuiContext& g = *GImGui;
9045 g.NextWindowData.BgAlphaVal = alpha;
9046}
9047
9049{
9050 ImGuiContext& g = *GImGui;
9053}
9054
9056{
9057 ImGuiContext& g = *GImGui;
9059 g.NextWindowData.DockCond = cond ? cond : ImGuiCond_Always;
9060 g.NextWindowData.DockId = id;
9061}
9062
9064{
9065 ImGuiContext& g = *GImGui;
9066 IM_ASSERT((window_class->ViewportFlagsOverrideSet & window_class->ViewportFlagsOverrideClear) == 0); // Cannot set both set and clear for the same bit
9068 g.NextWindowData.WindowClass = *window_class;
9069}
9070
9071// This is experimental and meant to be a toy for exploring a future/wider range of features.
9073{
9074 ImGuiContext& g = *GImGui;
9077}
9078
9080{
9081 ImGuiWindow* window = GetCurrentWindow();
9082 return window->DrawList;
9083}
9084
9086{
9087 ImGuiContext& g = *GImGui;
9088 return g.CurrentDpiScale;
9089}
9090
9092{
9093 ImGuiContext& g = *GImGui;
9095 return g.CurrentViewport;
9096}
9097
9099{
9100 return GImGui->Font;
9101}
9102
9104{
9105 return GImGui->FontBaked;
9106}
9107
9108// Get current font size (= height in pixels) of current font, with global scale factors applied.
9109// - Use style.FontSizeBase to get value before global scale factors.
9110// - recap: ImGui::GetFontSize() == style.FontSizeBase * (style.FontScaleMain * style.FontScaleDpi * other_scaling_factors)
9112{
9113 return GImGui->FontSize;
9114}
9115
9117{
9119}
9120
9121// Prefer using PushFont(NULL, style.FontSizeBase * factor), or use style.FontScaleMain to scale all windows.
9122#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
9124{
9125 IM_ASSERT(scale > 0.0f);
9126 ImGuiWindow* window = GetCurrentWindow();
9127 window->FontWindowScale = scale;
9129}
9130#endif
9131
9133{
9134 ImGuiContext& g = *GImGui;
9136 data.ID = id;
9137 data.WindowID = g.CurrentWindow->ID;
9138 g.FocusScopeStack.push_back(data);
9139 g.CurrentFocusScopeId = id;
9140}
9141
9143{
9144 ImGuiContext& g = *GImGui;
9146 {
9147 IM_ASSERT_USER_ERROR(0, "Calling PopFocusScope() too many times!");
9148 return;
9149 }
9152}
9153
9155{
9156 ImGuiContext& g = *GImGui;
9157 g.NavFocusScopeId = focus_scope_id;
9158 g.NavFocusRoute.resize(0); // Invalidate
9159 if (focus_scope_id == 0)
9160 return;
9161 IM_ASSERT(g.NavWindow != NULL);
9162
9163 // Store current path (in reverse order)
9164 if (focus_scope_id == g.CurrentFocusScopeId)
9165 {
9166 // Top of focus stack contains local focus scopes inside current window
9167 for (int n = g.FocusScopeStack.Size - 1; n >= 0 && g.FocusScopeStack.Data[n].WindowID == g.CurrentWindow->ID; n--)
9169 }
9170 else if (focus_scope_id == g.NavWindow->NavRootFocusScopeId)
9171 g.NavFocusRoute.push_back({ focus_scope_id, g.NavWindow->ID });
9172 else
9173 return;
9174
9175 // Then follow on manually set ParentWindowForFocusRoute field (#6798)
9176 for (ImGuiWindow* window = g.NavWindow->ParentWindowForFocusRoute; window != NULL; window = window->ParentWindowForFocusRoute)
9177 g.NavFocusRoute.push_back({ window->NavRootFocusScopeId, window->ID });
9178 IM_ASSERT(g.NavFocusRoute.Size < 100); // Maximum depth is technically 251 as per CalcRoutingScore(): 254 - 3
9179}
9180
9181// Focus = move navigation cursor, set scrolling, set focus window.
9183{
9184 ImGuiContext& g = *GImGui;
9185 ImGuiWindow* window = g.CurrentWindow;
9186 IMGUI_DEBUG_LOG_FOCUS("FocusItem(0x%08x) in window \"%s\"\n", g.LastItemData.ID, window->Name);
9187 if (g.DragDropActive || g.MovingWindow != NULL) // FIXME: Opt-in flags for this?
9188 {
9189 IMGUI_DEBUG_LOG_FOCUS("FocusItem() ignored while DragDropActive!\n");
9190 return;
9191 }
9192
9195 SetNavWindow(window);
9196 NavMoveRequestSubmit(ImGuiDir_None, ImGuiDir_Up, move_flags, scroll_flags);
9198}
9199
9201{
9202 ImGuiContext& g = *GImGui;
9203 g.NavNextActivateId = id;
9205}
9206
9207// Note: this will likely be called ActivateItem() once we rework our Focus/Activation system!
9208// But ActivateItem() should function without altering scroll/focus?
9210{
9211 ImGuiContext& g = *GImGui;
9212 ImGuiWindow* window = g.CurrentWindow;
9213 IM_ASSERT(offset >= -1); // -1 is allowed but not below
9214 IMGUI_DEBUG_LOG_FOCUS("SetKeyboardFocusHere(%d) in window \"%s\"\n", offset, window->Name);
9215
9216 // It makes sense in the vast majority of cases to never interrupt a drag and drop.
9217 // When we refactor this function into ActivateItem() we may want to make this an option.
9218 // MovingWindow is protected from most user inputs using SetActiveIdUsingNavAndKeys(), but
9219 // is also automatically dropped in the event g.ActiveId is stolen.
9220 if (g.DragDropActive || g.MovingWindow != NULL)
9221 {
9222 IMGUI_DEBUG_LOG_FOCUS("SetKeyboardFocusHere() ignored while DragDropActive!\n");
9223 return;
9224 }
9225
9226 SetNavWindow(window);
9227
9230 NavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, move_flags, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable.
9231 if (offset == -1)
9232 {
9234 }
9235 else
9236 {
9237 g.NavTabbingDir = 1;
9238 g.NavTabbingCounter = offset + 1;
9239 }
9240}
9241
9243{
9244 ImGuiContext& g = *GImGui;
9245 ImGuiWindow* window = g.CurrentWindow;
9246 if (!window->Appearing)
9247 return;
9248 if (g.NavWindow != window->RootWindowForNav || (!g.NavInitRequest && g.NavInitResult.ID == 0) || g.NavLayer != window->DC.NavLayerCurrent)
9249 return;
9250
9251 g.NavInitRequest = false;
9254
9255 // Scroll could be done in NavInitRequestApplyResult() via an opt-in flag (we however don't want regular init requests to scroll)
9256 if (!window->ClipRect.Contains(g.LastItemData.Rect))
9258}
9259
9261{
9262 ImGuiWindow* window = GImGui->CurrentWindow;
9263 window->DC.StateStorage = tree ? tree : &window->StateStorage;
9264}
9265
9267{
9268 ImGuiWindow* window = GImGui->CurrentWindow;
9269 return window->DC.StateStorage;
9270}
9271
9273{
9274 ImGuiWindow* window = GImGui->CurrentWindow;
9275 return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
9276}
9277
9278bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
9279{
9280 ImGuiWindow* window = GImGui->CurrentWindow;
9281 return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
9282}
9283
9284//-----------------------------------------------------------------------------
9285// [SECTION] FONTS
9286//-----------------------------------------------------------------------------
9287// Most of the relevant font logic is in imgui_draw.cpp.
9288// Those are high-level support functions.
9289//-----------------------------------------------------------------------------
9290// - UpdateFontsNewFrame() [Internal]
9291// - UpdateFontsEndFrame() [Internal]
9292// - GetDefaultFont() [Internal]
9293// - RegisterUserTexture() [Internal]
9294// - UnregisterUserTexture() [Internal]
9295// - RegisterFontAtlas() [Internal]
9296// - UnregisterFontAtlas() [Internal]
9297// - SetCurrentFont() [Internal]
9298// - UpdateCurrentFontSize() [Internal]
9299// - SetFontRasterizerDensity() [Internal]
9300// - PushFont()
9301// - PopFont()
9302//-----------------------------------------------------------------------------
9303
9305{
9306 ImGuiContext& g = *GImGui;
9308 for (ImFontAtlas* atlas : g.FontAtlases)
9309 atlas->Locked = true;
9310
9311 if (g.Style._NextFrameFontSizeBase != 0.0f)
9312 {
9315 }
9316
9317 // Apply default font size the first time
9318 ImFont* font = ImGui::GetDefaultFont();
9319 if (g.Style.FontSizeBase <= 0.0f)
9320 g.Style.FontSizeBase = (font->LegacySize > 0.0f ? font->LegacySize : FONT_DEFAULT_SIZE);
9321
9322 // Set initial font
9323 g.Font = font;
9325 g.FontSize = 0.0f;
9326 ImFontStackData font_stack_data = { font, g.Style.FontSizeBase, g.Style.FontSizeBase }; // <--- Will restore FontSize
9327 SetCurrentFont(font_stack_data.Font, font_stack_data.FontSizeBeforeScaling, 0.0f); // <--- but use 0.0f to enable scale
9328 g.FontStack.push_back(font_stack_data);
9329 IM_ASSERT(g.Font->IsLoaded());
9330}
9331
9333{
9334 PopFont();
9335}
9336
9338{
9339 ImGuiContext& g = *GImGui;
9340 ImFontAtlas* atlas = g.IO.Fonts;
9341 if (atlas->Builder == NULL || atlas->Fonts.Size == 0)
9342 ImFontAtlasBuildMain(atlas);
9343 return g.IO.FontDefault ? g.IO.FontDefault : atlas->Fonts[0];
9344}
9345
9347{
9348 ImGuiContext& g = *GImGui;
9349 IM_ASSERT(tex->RefCount > 0);
9350 g.UserTextures.push_back(tex);
9351}
9352
9354{
9355 ImGuiContext& g = *GImGui;
9356 g.UserTextures.find_erase(tex);
9357}
9358
9360{
9361 ImGuiContext& g = *GImGui;
9362 if (g.FontAtlases.Size == 0)
9363 IM_ASSERT(atlas == g.IO.Fonts);
9364 atlas->RefCount++;
9365 g.FontAtlases.push_back(atlas);
9367}
9368
9370{
9371 ImGuiContext& g = *GImGui;
9372 IM_ASSERT(atlas->RefCount > 0);
9374 g.FontAtlases.find_erase(atlas);
9375 atlas->RefCount--;
9376}
9377
9378// Use ImDrawList::_SetTexture(), making our shared g.FontStack[] authoritative against window-local ImDrawList.
9379// - Whereas ImDrawList::PushTexture()/PopTexture() is not to be used across Begin() calls.
9380// - Note that we don't propagate current texture id when e.g. Begin()-ing into a new window, we never really did...
9381// - Some code paths never really fully worked with multiple atlas textures.
9382// - The right-ish solution may be to remove _SetTexture() and make AddText/RenderText lazily call PushTexture()/PopTexture()
9383// the same way AddImage() does, but then all other primitives would also need to? I don't think we should tackle this problem
9384// because we have a concrete need and a test bed for multiple atlas textures.
9385// FIXME-NEWATLAS-V2: perhaps we can now leverage ImFontAtlasUpdateDrawListsTextures() ?
9386void ImGui::SetCurrentFont(ImFont* font, float font_size_before_scaling, float font_size_after_scaling)
9387{
9388 ImGuiContext& g = *GImGui;
9389 g.Font = font;
9390 g.FontSizeBase = font_size_before_scaling;
9391 UpdateCurrentFontSize(font_size_after_scaling);
9392
9393 if (font != NULL)
9394 {
9395 IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
9396#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
9397 IM_ASSERT(font->Scale > 0.0f);
9398#endif
9399 ImFontAtlas* atlas = font->ContainerAtlas;
9400 g.DrawListSharedData.FontAtlas = atlas;
9401 g.DrawListSharedData.Font = font;
9403 if (g.CurrentWindow != NULL)
9405 }
9406}
9407
9408void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling)
9409{
9410 ImGuiContext& g = *GImGui;
9411 ImGuiWindow* window = g.CurrentWindow;
9412
9414
9415 // Early out to avoid hidden window keeping bakes referenced and out of GC reach.
9416 // However this would leave a pretty subtle and damning error surface area if g.FontBaked was mismatching, so for now we null it.
9417 // FIXME: perhaps g.FontSize should be updated?
9418 if (window != NULL && window->SkipItems)
9419 if (g.CurrentTable == NULL || g.CurrentTable->CurrentColumn != -1) // See 8465#issuecomment-2951509561. Ideally the SkipItems=true in tables would be amended with extra data.
9420 return;
9421
9422 // Restoring is pretty much only used by PopFont()
9423 float final_size = (restore_font_size_after_scaling > 0.0f) ? restore_font_size_after_scaling : 0.0f;
9424 if (final_size == 0.0f)
9425 {
9426 final_size = g.FontSizeBase;
9427
9428 // Global scale factors
9429 final_size *= g.Style.FontScaleMain; // Main global scale factor
9430 final_size *= g.Style.FontScaleDpi; // Per-monitor/viewport DPI scale factor, automatically updated when io.ConfigDpiScaleFonts is enabled.
9431
9432 // Window scale (mostly obsolete now)
9433 if (window != NULL)
9434 final_size *= window->FontWindowScale;
9435
9436 // Legacy scale factors
9437#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
9438 final_size *= g.IO.FontGlobalScale; // Use style.FontScaleMain instead!
9439 if (g.Font != NULL)
9440 final_size *= g.Font->Scale; // Was never really useful.
9441#endif
9442 }
9443
9444 // Round font size
9445 // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet.
9446 // - We may support it better later and remove this rounding.
9447 final_size = GetRoundedFontSize(final_size);
9448 final_size = ImClamp(final_size, 1.0f, IMGUI_FONT_SIZE_MAX);
9451 g.FontSize = final_size;
9452 g.FontBaked = (g.Font != NULL && window != NULL) ? g.Font->GetFontBaked(final_size) : NULL;
9453 g.FontBakedScale = (g.Font != NULL && window != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f;
9456}
9457
9458// Exposed in case user may want to override setting density.
9459// IMPORTANT: Begin()/End() is overriding density. Be considerate of this you change it.
9460void ImGui::SetFontRasterizerDensity(float rasterizer_density)
9461{
9462 ImGuiContext& g = *GImGui;
9464 if (g.FontRasterizerDensity == rasterizer_density)
9465 return;
9466 g.FontRasterizerDensity = rasterizer_density;
9468}
9469
9470// If you want to scale an existing font size! Read comments in imgui.h!
9471void ImGui::PushFont(ImFont* font, float font_size_base)
9472{
9473 ImGuiContext& g = *GImGui;
9474 if (font == NULL) // Before 1.92 (June 2025), PushFont(NULL) == PushFont(GetDefaultFont())
9475 font = g.Font;
9476 IM_ASSERT(font != NULL);
9477 IM_ASSERT(font_size_base >= 0.0f);
9478
9480 if (font_size_base == 0.0f)
9481 font_size_base = g.FontSizeBase; // Keep current font size
9482 SetCurrentFont(font, font_size_base, 0.0f);
9483}
9484
9486{
9487 ImGuiContext& g = *GImGui;
9488 if (g.FontStack.Size <= 0)
9489 {
9490 IM_ASSERT_USER_ERROR(0, "Calling PopFont() too many times!");
9491 return;
9492 }
9493 ImFontStackData* font_stack_data = &g.FontStack.back();
9494 SetCurrentFont(font_stack_data->Font, font_stack_data->FontSizeBeforeScaling, font_stack_data->FontSizeAfterScaling);
9495 g.FontStack.pop_back();
9496}
9497
9498//-----------------------------------------------------------------------------
9499// [SECTION] ID STACK
9500//-----------------------------------------------------------------------------
9501
9502// This is one of the very rare legacy case where we use ImGuiWindow methods,
9503// it should ideally be flattened at some point but it's been used a lots by widgets.
9505ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
9506{
9507 ImGuiID seed = IDStack.back();
9508 ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
9509#ifndef IMGUI_DISABLE_DEBUG_TOOLS
9510 ImGuiContext& g = *Ctx;
9511 if (g.DebugHookIdInfo == id)
9513#endif
9514 return id;
9515}
9516
9518{
9519 ImGuiID seed = IDStack.back();
9520 ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
9521#ifndef IMGUI_DISABLE_DEBUG_TOOLS
9522 ImGuiContext& g = *Ctx;
9523 if (g.DebugHookIdInfo == id)
9525#endif
9526 return id;
9527}
9528
9530{
9531 ImGuiID seed = IDStack.back();
9532 ImGuiID id = ImHashData(&n, sizeof(n), seed);
9533#ifndef IMGUI_DISABLE_DEBUG_TOOLS
9534 ImGuiContext& g = *Ctx;
9535 if (g.DebugHookIdInfo == id)
9536 ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
9537#endif
9538 return id;
9539}
9540
9541// This is only used in rare/specific situations to manufacture an ID out of nowhere.
9542// FIXME: Consider instead storing last non-zero ID + count of successive zero-ID, and combine those?
9544{
9545 ImGuiID seed = IDStack.back();
9546 ImVec2 p_rel = ImGui::WindowPosAbsToRel(this, p_abs);
9547 ImGuiID id = ImHashData(&p_rel, sizeof(p_rel), seed);
9548 return id;
9549}
9550
9551// "
9553{
9554 ImGuiID seed = IDStack.back();
9555 ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs);
9556 ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
9557 return id;
9558}
9559
9560void ImGui::PushID(const char* str_id)
9561{
9562 ImGuiContext& g = *GImGui;
9563 ImGuiWindow* window = g.CurrentWindow;
9564 ImGuiID id = window->GetID(str_id);
9565 window->IDStack.push_back(id);
9566}
9567
9568void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
9569{
9570 ImGuiContext& g = *GImGui;
9571 ImGuiWindow* window = g.CurrentWindow;
9572 ImGuiID id = window->GetID(str_id_begin, str_id_end);
9573 window->IDStack.push_back(id);
9574}
9575
9576void ImGui::PushID(const void* ptr_id)
9577{
9578 ImGuiContext& g = *GImGui;
9579 ImGuiWindow* window = g.CurrentWindow;
9580 ImGuiID id = window->GetID(ptr_id);
9581 window->IDStack.push_back(id);
9582}
9583
9584void ImGui::PushID(int int_id)
9585{
9586 ImGuiContext& g = *GImGui;
9587 ImGuiWindow* window = g.CurrentWindow;
9588 ImGuiID id = window->GetID(int_id);
9589 window->IDStack.push_back(id);
9590}
9591
9592// Push a given id value ignoring the ID stack as a seed.
9594{
9595 ImGuiContext& g = *GImGui;
9596 ImGuiWindow* window = g.CurrentWindow;
9597#ifndef IMGUI_DISABLE_DEBUG_TOOLS
9598 if (g.DebugHookIdInfo == id)
9599 DebugHookIdInfo(id, ImGuiDataType_ID, NULL, NULL);
9600#endif
9601 window->IDStack.push_back(id);
9602}
9603
9604// Helper to avoid a common series of PushOverrideID -> GetID() -> PopID() call
9605// (note that when using this pattern, ID Stack Tool will tend to not display the intermediate stack level.
9606// for that to work we would need to do PushOverrideID() -> ItemAdd() -> PopID() which would alter widget code a little more)
9607ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
9608{
9609 ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
9610#ifndef IMGUI_DISABLE_DEBUG_TOOLS
9611 ImGuiContext& g = *GImGui;
9612 if (g.DebugHookIdInfo == id)
9613 DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
9614#endif
9615 return id;
9616}
9617
9619{
9620 ImGuiID id = ImHashData(&n, sizeof(n), seed);
9621#ifndef IMGUI_DISABLE_DEBUG_TOOLS
9622 ImGuiContext& g = *GImGui;
9623 if (g.DebugHookIdInfo == id)
9624 DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
9625#endif
9626 return id;
9627}
9628
9630{
9631 ImGuiWindow* window = GImGui->CurrentWindow;
9632 if (window->IDStack.Size <= 1)
9633 {
9634 IM_ASSERT_USER_ERROR(0, "Calling PopID() too many times!");
9635 return;
9636 }
9637 window->IDStack.pop_back();
9638}
9639
9640ImGuiID ImGui::GetID(const char* str_id)
9641{
9642 ImGuiWindow* window = GImGui->CurrentWindow;
9643 return window->GetID(str_id);
9644}
9645
9646ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
9647{
9648 ImGuiWindow* window = GImGui->CurrentWindow;
9649 return window->GetID(str_id_begin, str_id_end);
9650}
9651
9652ImGuiID ImGui::GetID(const void* ptr_id)
9653{
9654 ImGuiWindow* window = GImGui->CurrentWindow;
9655 return window->GetID(ptr_id);
9656}
9657
9659{
9660 ImGuiWindow* window = GImGui->CurrentWindow;
9661 return window->GetID(int_id);
9662}
9664
9665//-----------------------------------------------------------------------------
9666// [SECTION] INPUTS
9667//-----------------------------------------------------------------------------
9668// - GetModForLRModKey() [Internal]
9669// - FixupKeyChord() [Internal]
9670// - GetKeyData() [Internal]
9671// - GetKeyIndex() [Internal]
9672// - GetKeyName()
9673// - GetKeyChordName() [Internal]
9674// - CalcTypematicRepeatAmount() [Internal]
9675// - GetTypematicRepeatRate() [Internal]
9676// - GetKeyPressedAmount() [Internal]
9677// - GetKeyMagnitude2d() [Internal]
9678//-----------------------------------------------------------------------------
9679// - UpdateKeyRoutingTable() [Internal]
9680// - GetRoutingIdFromOwnerId() [Internal]
9681// - GetShortcutRoutingData() [Internal]
9682// - CalcRoutingScore() [Internal]
9683// - SetShortcutRouting() [Internal]
9684// - TestShortcutRouting() [Internal]
9685//-----------------------------------------------------------------------------
9686// - IsKeyDown()
9687// - IsKeyPressed()
9688// - IsKeyReleased()
9689//-----------------------------------------------------------------------------
9690// - IsMouseDown()
9691// - IsMouseClicked()
9692// - IsMouseReleased()
9693// - IsMouseDoubleClicked()
9694// - GetMouseClickedCount()
9695// - IsMouseHoveringRect() [Internal]
9696// - IsMouseDragPastThreshold() [Internal]
9697// - IsMouseDragging()
9698// - GetMousePos()
9699// - SetMousePos() [Internal]
9700// - GetMousePosOnOpeningCurrentPopup()
9701// - IsMousePosValid()
9702// - IsAnyMouseDown()
9703// - GetMouseDragDelta()
9704// - ResetMouseDragDelta()
9705// - GetMouseCursor()
9706// - SetMouseCursor()
9707//-----------------------------------------------------------------------------
9708// - UpdateAliasKey()
9709// - GetMergedModsFromKeys()
9710// - UpdateKeyboardInputs()
9711// - UpdateMouseInputs()
9712//-----------------------------------------------------------------------------
9713// - LockWheelingWindow [Internal]
9714// - FindBestWheelingWindow [Internal]
9715// - UpdateMouseWheel() [Internal]
9716//-----------------------------------------------------------------------------
9717// - SetNextFrameWantCaptureKeyboard()
9718// - SetNextFrameWantCaptureMouse()
9719//-----------------------------------------------------------------------------
9720// - GetInputSourceName() [Internal]
9721// - DebugPrintInputEvent() [Internal]
9722// - UpdateInputEvents() [Internal]
9723//-----------------------------------------------------------------------------
9724// - GetKeyOwner() [Internal]
9725// - TestKeyOwner() [Internal]
9726// - SetKeyOwner() [Internal]
9727// - SetItemKeyOwner() [Internal]
9728// - Shortcut() [Internal]
9729//-----------------------------------------------------------------------------
9730
9732{
9733 if (key == ImGuiKey_LeftCtrl || key == ImGuiKey_RightCtrl)
9734 return ImGuiMod_Ctrl;
9735 if (key == ImGuiKey_LeftShift || key == ImGuiKey_RightShift)
9736 return ImGuiMod_Shift;
9737 if (key == ImGuiKey_LeftAlt || key == ImGuiKey_RightAlt)
9738 return ImGuiMod_Alt;
9739 if (key == ImGuiKey_LeftSuper || key == ImGuiKey_RightSuper)
9740 return ImGuiMod_Super;
9741 return ImGuiMod_None;
9742}
9743
9745{
9746 // Add ImGuiMod_XXXX when a corresponding ImGuiKey_LeftXXX/ImGuiKey_RightXXX is specified.
9747 ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
9748 if (IsLRModKey(key))
9749 key_chord |= GetModForLRModKey(key);
9750 return key_chord;
9751}
9752
9754{
9755 ImGuiContext& g = *ctx;
9756
9757 // Special storage location for mods
9758 if (key & ImGuiMod_Mask_)
9759 key = ConvertSingleModFlagToKey(key);
9760
9761 IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend & user code.");
9762 return &g.IO.KeysData[key - ImGuiKey_NamedKey_BEGIN];
9763}
9764
9765// Those names are provided for debugging purpose and are not meant to be saved persistently nor compared.
9766static const char* const GKeyNames[] =
9767{
9768 "Tab", "LeftArrow", "RightArrow", "UpArrow", "DownArrow", "PageUp", "PageDown",
9769 "Home", "End", "Insert", "Delete", "Backspace", "Space", "Enter", "Escape",
9770 "LeftCtrl", "LeftShift", "LeftAlt", "LeftSuper", "RightCtrl", "RightShift", "RightAlt", "RightSuper", "Menu",
9771 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
9772 "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
9773 "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
9774 "F13", "F14", "F15", "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24",
9775 "Apostrophe", "Comma", "Minus", "Period", "Slash", "Semicolon", "Equal", "LeftBracket",
9776 "Backslash", "RightBracket", "GraveAccent", "CapsLock", "ScrollLock", "NumLock", "PrintScreen",
9777 "Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6",
9778 "Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply",
9779 "KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual",
9780 "AppBack", "AppForward", "Oem102",
9781 "GamepadStart", "GamepadBack",
9782 "GamepadFaceLeft", "GamepadFaceRight", "GamepadFaceUp", "GamepadFaceDown",
9783 "GamepadDpadLeft", "GamepadDpadRight", "GamepadDpadUp", "GamepadDpadDown",
9784 "GamepadL1", "GamepadR1", "GamepadL2", "GamepadR2", "GamepadL3", "GamepadR3",
9785 "GamepadLStickLeft", "GamepadLStickRight", "GamepadLStickUp", "GamepadLStickDown",
9786 "GamepadRStickLeft", "GamepadRStickRight", "GamepadRStickUp", "GamepadRStickDown",
9787 "MouseLeft", "MouseRight", "MouseMiddle", "MouseX1", "MouseX2", "MouseWheelX", "MouseWheelY",
9788 "ModCtrl", "ModShift", "ModAlt", "ModSuper", // ReservedForModXXX are showing the ModXXX names.
9789};
9791
9793{
9794 if (key == ImGuiKey_None)
9795 return "None";
9796 IM_ASSERT(IsNamedKeyOrMod(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code.");
9797 if (key & ImGuiMod_Mask_)
9798 key = ConvertSingleModFlagToKey(key);
9799 if (!IsNamedKey(key))
9800 return "Unknown";
9801
9802 return GKeyNames[key - ImGuiKey_NamedKey_BEGIN];
9803}
9804
9805// Return untranslated names: on macOS, Cmd key will show as Ctrl, Ctrl key will show as super.
9806// Lifetime of return value: valid until next call to same function.
9808{
9809 ImGuiContext& g = *GImGui;
9810
9811 const ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
9812 if (IsLRModKey(key))
9813 key_chord &= ~GetModForLRModKey(key); // Return "Ctrl+LeftShift" instead of "Ctrl+Shift+LeftShift"
9815 (key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "",
9816 (key_chord & ImGuiMod_Shift) ? "Shift+" : "",
9817 (key_chord & ImGuiMod_Alt) ? "Alt+" : "",
9818 (key_chord & ImGuiMod_Super) ? "Super+" : "",
9819 (key != ImGuiKey_None || key_chord == ImGuiKey_None) ? GetKeyName(key) : "");
9820 size_t len;
9821 if (key == ImGuiKey_None && key_chord != 0)
9822 if ((len = ImStrlen(g.TempKeychordName)) != 0) // Remove trailing '+'
9823 g.TempKeychordName[len - 1] = 0;
9824 return g.TempKeychordName;
9825}
9826
9827// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
9828// t1 = current time (e.g.: g.Time)
9829// An event is triggered at:
9830// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N
9831int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate)
9832{
9833 if (t1 == 0.0f)
9834 return 1;
9835 if (t0 >= t1)
9836 return 0;
9837 if (repeat_rate <= 0.0f)
9838 return (t0 < repeat_delay) && (t1 >= repeat_delay);
9839 const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate);
9840 const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate);
9841 const int count = count_t1 - count_t0;
9842 return count;
9843}
9844
9845void ImGui::GetTypematicRepeatRate(ImGuiInputFlags flags, float* repeat_delay, float* repeat_rate)
9846{
9847 ImGuiContext& g = *GImGui;
9848 switch (flags & ImGuiInputFlags_RepeatRateMask_)
9849 {
9850 case ImGuiInputFlags_RepeatRateNavMove: *repeat_delay = g.IO.KeyRepeatDelay * 0.72f; *repeat_rate = g.IO.KeyRepeatRate * 0.80f; return;
9851 case ImGuiInputFlags_RepeatRateNavTweak: *repeat_delay = g.IO.KeyRepeatDelay * 0.72f; *repeat_rate = g.IO.KeyRepeatRate * 0.30f; return;
9852 case ImGuiInputFlags_RepeatRateDefault: default: *repeat_delay = g.IO.KeyRepeatDelay * 1.00f; *repeat_rate = g.IO.KeyRepeatRate * 1.00f; return;
9853 }
9854}
9855
9856// Return value representing the number of presses in the last time period, for the given repeat rate
9857// (most often returns 0 or 1. The result is generally only >1 when RepeatRate is smaller than DeltaTime, aka large DeltaTime or fast RepeatRate)
9858int ImGui::GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float repeat_rate)
9859{
9860 ImGuiContext& g = *GImGui;
9861 const ImGuiKeyData* key_data = GetKeyData(key);
9862 if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership)
9863 return 0;
9864 const float t = key_data->DownDuration;
9865 return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate);
9866}
9867
9868// Return 2D vector representing the combination of four cardinal direction, with analog value support (for e.g. ImGuiKey_GamepadLStick* values).
9870{
9871 return ImVec2(
9872 GetKeyData(key_right)->AnalogValue - GetKeyData(key_left)->AnalogValue,
9873 GetKeyData(key_down)->AnalogValue - GetKeyData(key_up)->AnalogValue);
9874}
9875
9876// Rewrite routing data buffers to strip old entries + sort by key to make queries not touch scattered data.
9877// Entries D,A,B,B,A,C,B --> A,A,B,B,B,C,D
9878// Index A:1 B:2 C:5 D:0 --> A:0 B:2 C:5 D:6
9879// See 'Metrics->Key Owners & Shortcut Routing' to visualize the result of that operation.
9881{
9882 ImGuiContext& g = *GImGui;
9883 rt->EntriesNext.resize(0);
9884 for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
9885 {
9886 const int new_routing_start_idx = rt->EntriesNext.Size;
9887 ImGuiKeyRoutingData* routing_entry;
9888 for (int old_routing_idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; old_routing_idx != -1; old_routing_idx = routing_entry->NextEntryIndex)
9889 {
9890 routing_entry = &rt->Entries[old_routing_idx];
9891 routing_entry->RoutingCurrScore = routing_entry->RoutingNextScore;
9892 routing_entry->RoutingCurr = routing_entry->RoutingNext; // Update entry
9893 routing_entry->RoutingNext = ImGuiKeyOwner_NoOwner;
9894 routing_entry->RoutingNextScore = 255;
9895 if (routing_entry->RoutingCurr == ImGuiKeyOwner_NoOwner)
9896 continue;
9897 rt->EntriesNext.push_back(*routing_entry); // Write alive ones into new buffer
9898
9899 // Apply routing to owner if there's no owner already (RoutingCurr == None at this point)
9900 // This is the result of previous frame's SetShortcutRouting() call.
9901 if (routing_entry->Mods == g.IO.KeyMods)
9902 {
9903 ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
9904 if (owner_data->OwnerCurr == ImGuiKeyOwner_NoOwner)
9905 {
9906 owner_data->OwnerCurr = routing_entry->RoutingCurr;
9907 //IMGUI_DEBUG_LOG("SetKeyOwner(%s, owner_id=0x%08X) via Routing\n", GetKeyName(key), routing_entry->RoutingCurr);
9908 }
9909 }
9910 }
9911
9912 // Rewrite linked-list
9913 rt->Index[key - ImGuiKey_NamedKey_BEGIN] = (ImGuiKeyRoutingIndex)(new_routing_start_idx < rt->EntriesNext.Size ? new_routing_start_idx : -1);
9914 for (int n = new_routing_start_idx; n < rt->EntriesNext.Size; n++)
9915 rt->EntriesNext[n].NextEntryIndex = (ImGuiKeyRoutingIndex)((n + 1 < rt->EntriesNext.Size) ? n + 1 : -1);
9916 }
9917 rt->Entries.swap(rt->EntriesNext); // Swap new and old indexes
9918}
9919
9920// owner_id may be None/Any, but routing_id needs to be always be set, so we default to GetCurrentFocusScope().
9922{
9923 ImGuiContext& g = *GImGui;
9924 return (owner_id != ImGuiKeyOwner_NoOwner && owner_id != ImGuiKeyOwner_Any) ? owner_id : g.CurrentFocusScopeId;
9925}
9926
9928{
9929 // Majority of shortcuts will be Key + any number of Mods
9930 // We accept _Single_ mod with ImGuiKey_None.
9931 // - Shortcut(ImGuiKey_S | ImGuiMod_Ctrl); // Legal
9932 // - Shortcut(ImGuiKey_S | ImGuiMod_Ctrl | ImGuiMod_Shift); // Legal
9933 // - Shortcut(ImGuiMod_Ctrl); // Legal
9934 // - Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift); // Not legal
9935 ImGuiContext& g = *GImGui;
9937 ImGuiKeyRoutingData* routing_data;
9938 ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
9939 ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);
9940 if (key == ImGuiKey_None)
9941 key = ConvertSingleModFlagToKey(mods);
9942 IM_ASSERT(IsNamedKey(key));
9943
9944 // Get (in the majority of case, the linked list will have one element so this should be 2 reads.
9945 // Subsequent elements will be contiguous in memory as list is sorted/rebuilt in NewFrame).
9946 for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; idx = routing_data->NextEntryIndex)
9947 {
9948 routing_data = &rt->Entries[idx];
9949 if (routing_data->Mods == mods)
9950 return routing_data;
9951 }
9952
9953 // Add to linked-list
9954 ImGuiKeyRoutingIndex routing_data_idx = (ImGuiKeyRoutingIndex)rt->Entries.Size;
9956 routing_data = &rt->Entries[routing_data_idx];
9957 routing_data->Mods = (ImU16)mods;
9958 routing_data->NextEntryIndex = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; // Setup linked list
9959 rt->Index[key - ImGuiKey_NamedKey_BEGIN] = routing_data_idx;
9960 return routing_data;
9961}
9962
9963// Current score encoding (lower is highest priority):
9964// - 0: ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive
9965// - 1: ImGuiInputFlags_ActiveItem or ImGuiInputFlags_RouteFocused (if item active)
9966// - 2: ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused
9967// - 3+: ImGuiInputFlags_RouteFocused (if window in focus-stack)
9968// - 254: ImGuiInputFlags_RouteGlobal
9969// - 255: never route
9970// 'flags' should include an explicit routing policy
9971static int CalcRoutingScore(ImGuiID focus_scope_id, ImGuiID owner_id, ImGuiInputFlags flags)
9972{
9973 ImGuiContext& g = *GImGui;
9974 if (flags & ImGuiInputFlags_RouteFocused)
9975 {
9976 // ActiveID gets top priority
9977 // (we don't check g.ActiveIdUsingAllKeys here. Routing is applied but if input ownership is tested later it may discard it)
9978 if (owner_id != 0 && g.ActiveId == owner_id)
9979 return 1;
9980
9981 // Score based on distance to focused window (lower is better)
9982 // Assuming both windows are submitting a routing request,
9983 // - When Window....... is focused -> Window scores 3 (best), Window/ChildB scores 255 (no match)
9984 // - When Window/ChildB is focused -> Window scores 4, Window/ChildB scores 3 (best)
9985 // Assuming only WindowA is submitting a routing request,
9986 // - When Window/ChildB is focused -> Window scores 4 (best), Window/ChildB doesn't have a score.
9987 // This essentially follow the window->ParentWindowForFocusRoute chain.
9988 if (focus_scope_id == 0)
9989 return 255;
9990 for (int index_in_focus_path = 0; index_in_focus_path < g.NavFocusRoute.Size; index_in_focus_path++)
9991 if (g.NavFocusRoute.Data[index_in_focus_path].ID == focus_scope_id)
9992 return 3 + index_in_focus_path;
9993 return 255;
9994 }
9995 else if (flags & ImGuiInputFlags_RouteActive)
9996 {
9997 if (owner_id != 0 && g.ActiveId == owner_id)
9998 return 1;
9999 return 255;
10000 }
10001 else if (flags & ImGuiInputFlags_RouteGlobal)
10002 {
10004 return 0;
10006 return 2;
10007 return 254;
10008 }
10009 IM_ASSERT(0);
10010 return 0;
10011}
10012
10013// - We need this to filter some Shortcut() routes when an item e.g. an InputText() is active
10014// e.g. ImGuiKey_G won't be considered a shortcut when item is active, but ImGuiMod|ImGuiKey_G can be.
10015// - This is also used by UpdateInputEvents() to avoid trickling in the most common case of e.g. pressing ImGuiKey_G also emitting a G character.
10017{
10018 // Mimic 'ignore_char_inputs' logic in InputText()
10019 ImGuiContext& g = *GImGui;
10020
10021 // When the right mods are pressed it cannot be a char input so we won't filter the shortcut out.
10022 ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);
10023 const bool ignore_char_inputs = ((mods & ImGuiMod_Ctrl) && !(mods & ImGuiMod_Alt)) || (g.IO.ConfigMacOSXBehaviors && (mods & ImGuiMod_Ctrl));
10024 if (ignore_char_inputs)
10025 return false;
10026
10027 // Return true for A-Z, 0-9 and other keys associated to char inputs. Other keys such as F1-F12 won't be filtered.
10028 ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
10029 if (key == ImGuiKey_None)
10030 return false;
10031 return g.KeysMayBeCharInput.TestBit(key);
10032}
10033
10034// Request a desired route for an input chord (key + mods).
10035// Return true if the route is available this frame.
10036// - Routes and key ownership are attributed at the beginning of next frame based on best score and mod state.
10037// (Conceptually this does a "Submit for next frame" + "Test for current frame".
10038// As such, it could be called TrySetXXX or SubmitXXX, or the Submit and Test operations should be separate.)
10040{
10041 ImGuiContext& g = *GImGui;
10042 if ((flags & ImGuiInputFlags_RouteTypeMask_) == 0)
10043 flags |= ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive; // IMPORTANT: This is the default for SetShortcutRouting() but NOT Shortcut()
10044 else
10045 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteTypeMask_)); // Check that only 1 routing flag is used
10046 IM_ASSERT(owner_id != ImGuiKeyOwner_Any && owner_id != ImGuiKeyOwner_NoOwner);
10049
10050 // Add ImGuiMod_XXXX when a corresponding ImGuiKey_LeftXXX/ImGuiKey_RightXXX is specified.
10051 key_chord = FixupKeyChord(key_chord);
10052
10053 // [DEBUG] Debug break requested by user
10054 if (g.DebugBreakInShortcutRouting == key_chord)
10056
10058 if (g.NavWindow == NULL)
10059 return false;
10060
10061 // Note how ImGuiInputFlags_RouteAlways won't set routing and thus won't set owner. May want to rework this?
10062 if (flags & ImGuiInputFlags_RouteAlways)
10063 {
10064 IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, flags=%04X, owner_id=0x%08X) -> always, no register\n", GetKeyChordName(key_chord), flags, owner_id);
10065 return true;
10066 }
10067
10068 // Specific culling when there's an active item.
10069 if (g.ActiveId != 0 && g.ActiveId != owner_id)
10070 {
10071 if (flags & ImGuiInputFlags_RouteActive)
10072 return false;
10073
10074 // Cull shortcuts with no modifiers when it could generate a character.
10075 // e.g. Shortcut(ImGuiKey_G) also generates 'g' character, should not trigger when InputText() is active.
10076 // but Shortcut(Ctrl+G) should generally trigger when InputText() is active.
10077 // TL;DR: lettered shortcut with no mods or with only Alt mod will not trigger while an item reading text input is active.
10078 // (We cannot filter based on io.InputQueueCharacters[] contents because of trickling and key<>chars submission order are undefined)
10080 {
10081 IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, flags=%04X, owner_id=0x%08X) -> filtered as potential char input\n", GetKeyChordName(key_chord), flags, owner_id);
10082 return false;
10083 }
10084
10085 // ActiveIdUsingAllKeyboardKeys trumps all for ActiveId
10087 {
10088 ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
10089 if (key == ImGuiKey_None)
10092 return false;
10093 }
10094 }
10095
10096 // Where do we evaluate route for?
10097 ImGuiID focus_scope_id = g.CurrentFocusScopeId;
10099 focus_scope_id = g.CurrentWindow->RootWindow->ID; // See PushFocusScope() call in Begin()
10100
10101 const int score = CalcRoutingScore(focus_scope_id, owner_id, flags);
10102 IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, flags=%04X, owner_id=0x%08X) -> score %d\n", GetKeyChordName(key_chord), flags, owner_id, score);
10103 if (score == 255)
10104 return false;
10105
10106 // Submit routing for NEXT frame (assuming score is sufficient)
10107 // FIXME: Could expose a way to use a "serve last" policy for same score resolution (using <= instead of <).
10108 ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord);
10109 //const bool set_route = (flags & ImGuiInputFlags_ServeLast) ? (score <= routing_data->RoutingNextScore) : (score < routing_data->RoutingNextScore);
10110 if (score < routing_data->RoutingNextScore)
10111 {
10112 routing_data->RoutingNext = owner_id;
10113 routing_data->RoutingNextScore = (ImU8)score;
10114 }
10115
10116 // Return routing state for CURRENT frame
10117 if (routing_data->RoutingCurr == owner_id)
10118 IMGUI_DEBUG_LOG_INPUTROUTING("--> granting current route\n");
10119 return routing_data->RoutingCurr == owner_id;
10120}
10121
10122// Currently unused by core (but used by tests)
10123// Note: this cannot be turned into GetShortcutRouting() because we do the owner_id->routing_id translation, name would be more misleading.
10125{
10126 const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id);
10127 key_chord = FixupKeyChord(key_chord);
10128 ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); // FIXME: Could avoid creating entry.
10129 return routing_data->RoutingCurr == routing_id;
10130}
10131
10132// Note that Dear ImGui doesn't know the meaning/semantic of ImGuiKey from 0..511: they are legacy native keycodes.
10133// Consider transitioning from 'IsKeyDown(MY_ENGINE_KEY_A)' (<1.87) to IsKeyDown(ImGuiKey_A) (>= 1.87)
10135{
10136 return IsKeyDown(key, ImGuiKeyOwner_Any);
10137}
10138
10140{
10141 const ImGuiKeyData* key_data = GetKeyData(key);
10142 if (!key_data->Down)
10143 return false;
10144 if (!TestKeyOwner(key, owner_id))
10145 return false;
10146 return true;
10147}
10148
10149bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat)
10150{
10152}
10153
10154// Important: unlike legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat.
10156{
10157 const ImGuiKeyData* key_data = GetKeyData(key);
10158 if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership)
10159 return false;
10160 const float t = key_data->DownDuration;
10161 if (t < 0.0f)
10162 return false;
10163 IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function!
10164 if (flags & (ImGuiInputFlags_RepeatRateMask_ | ImGuiInputFlags_RepeatUntilMask_)) // Setting any _RepeatXXX option enables _Repeat
10165 flags |= ImGuiInputFlags_Repeat;
10166
10167 bool pressed = (t == 0.0f);
10168 if (!pressed && (flags & ImGuiInputFlags_Repeat) != 0)
10169 {
10170 float repeat_delay, repeat_rate;
10171 GetTypematicRepeatRate(flags, &repeat_delay, &repeat_rate);
10172 pressed = (t > repeat_delay) && GetKeyPressedAmount(key, repeat_delay, repeat_rate) > 0;
10173 if (pressed && (flags & ImGuiInputFlags_RepeatUntilMask_))
10174 {
10175 // Slightly bias 'key_pressed_time' as DownDuration is an accumulation of DeltaTime which we compare to an absolute time value.
10176 // Ideally we'd replace DownDuration with KeyPressedTime but it would break user's code.
10177 ImGuiContext& g = *GImGui;
10178 double key_pressed_time = g.Time - t + 0.00001f;
10179 if ((flags & ImGuiInputFlags_RepeatUntilKeyModsChange) && (g.LastKeyModsChangeTime > key_pressed_time))
10180 pressed = false;
10182 pressed = false;
10183 if ((flags & ImGuiInputFlags_RepeatUntilOtherKeyPress) && (g.LastKeyboardKeyPressTime > key_pressed_time))
10184 pressed = false;
10185 }
10186 }
10187 if (!pressed)
10188 return false;
10189 if (!TestKeyOwner(key, owner_id))
10190 return false;
10191 return true;
10192}
10193
10195{
10196 return IsKeyReleased(key, ImGuiKeyOwner_Any);
10197}
10198
10200{
10201 const ImGuiKeyData* key_data = GetKeyData(key);
10202 if (key_data->DownDurationPrev < 0.0f || key_data->Down)
10203 return false;
10204 if (!TestKeyOwner(key, owner_id))
10205 return false;
10206 return true;
10207}
10208
10210{
10211 ImGuiContext& g = *GImGui;
10212 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10213 return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // should be same as IsKeyDown(MouseButtonToKey(button), ImGuiKeyOwner_Any), but this allows legacy code hijacking the io.Mousedown[] array.
10214}
10215
10217{
10218 ImGuiContext& g = *GImGui;
10219 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10220 return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyDown(MouseButtonToKey(button), owner_id), but this allows legacy code hijacking the io.Mousedown[] array.
10221}
10222
10224{
10226}
10227
10229{
10230 ImGuiContext& g = *GImGui;
10231 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10232 if (!g.IO.MouseDown[button]) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership)
10233 return false;
10234 const float t = g.IO.MouseDownDuration[button];
10235 if (t < 0.0f)
10236 return false;
10237 IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsMouseClicked) == 0); // Passing flags not supported by this function! // FIXME: Could support RepeatRate and RepeatUntil flags here.
10238
10239 const bool repeat = (flags & ImGuiInputFlags_Repeat) != 0;
10240 const bool pressed = (t == 0.0f) || (repeat && t > g.IO.KeyRepeatDelay && CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0);
10241 if (!pressed)
10242 return false;
10243
10244 if (!TestKeyOwner(MouseButtonToKey(button), owner_id))
10245 return false;
10246
10247 return true;
10248}
10249
10251{
10252 ImGuiContext& g = *GImGui;
10253 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10254 return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // Should be same as IsKeyReleased(MouseButtonToKey(button), ImGuiKeyOwner_Any)
10255}
10256
10258{
10259 ImGuiContext& g = *GImGui;
10260 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10261 return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyReleased(MouseButtonToKey(button), owner_id)
10262}
10263
10264// Use if you absolutely need to distinguish single-click from double-click by introducing a delay.
10265// Generally use with 'delay >= io.MouseDoubleClickTime' + combined with a 'io.MouseClickedLastCount == 1' test.
10266// This is a very rarely used UI idiom, but some apps use this: e.g. MS Explorer single click on an icon to rename.
10268{
10269 ImGuiContext& g = *GImGui;
10270 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10271 const float time_since_release = (float)(g.Time - g.IO.MouseReleasedTime[button]);
10272 return !IsMouseDown(button) && (time_since_release - g.IO.DeltaTime < delay) && (time_since_release >= delay);
10273}
10274
10276{
10277 ImGuiContext& g = *GImGui;
10278 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10279 return g.IO.MouseClickedCount[button] == 2 && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any);
10280}
10281
10283{
10284 ImGuiContext& g = *GImGui;
10285 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10286 return g.IO.MouseClickedCount[button] == 2 && TestKeyOwner(MouseButtonToKey(button), owner_id);
10287}
10288
10290{
10291 ImGuiContext& g = *GImGui;
10292 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10293 return g.IO.MouseClickedCount[button];
10294}
10295
10296// Test if mouse cursor is hovering given rectangle
10297// NB- Rectangle is clipped by our current clip setting
10298// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
10299bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
10300{
10301 ImGuiContext& g = *GImGui;
10302
10303 // Clip
10304 ImRect rect_clipped(r_min, r_max);
10305 if (clip)
10306 rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
10307
10308 // Hit testing, expanded for touch input
10309 if (!rect_clipped.ContainsWithPad(g.IO.MousePos, g.Style.TouchExtraPadding))
10310 return false;
10311 if (!g.MouseViewport->GetMainRect().Overlaps(rect_clipped))
10312 return false;
10313 return true;
10314}
10315
10316// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame.
10317// [Internal] This doesn't test if the button is pressed
10318bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold)
10319{
10320 ImGuiContext& g = *GImGui;
10321 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10322 if (lock_threshold < 0.0f)
10323 lock_threshold = g.IO.MouseDragThreshold;
10324 return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
10325}
10326
10327bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold)
10328{
10329 ImGuiContext& g = *GImGui;
10330 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10331 if (!g.IO.MouseDown[button])
10332 return false;
10333 return IsMouseDragPastThreshold(button, lock_threshold);
10334}
10335
10337{
10338 ImGuiContext& g = *GImGui;
10339 return g.IO.MousePos;
10340}
10341
10342// This is called TeleportMousePos() and not SetMousePos() to emphasis that setting MousePosPrev will effectively clear mouse delta as well.
10343// It is expected you only call this if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) is set and supported by backend.
10345{
10346 ImGuiContext& g = *GImGui;
10347 g.IO.MousePos = g.IO.MousePosPrev = pos;
10348 g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
10349 g.IO.WantSetMousePos = true;
10350 //IMGUI_DEBUG_LOG_IO("TeleportMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y);
10351}
10352
10353// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
10355{
10356 ImGuiContext& g = *GImGui;
10357 if (g.BeginPopupStack.Size > 0)
10358 return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos;
10359 return g.IO.MousePos;
10360}
10361
10362// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position.
10363bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
10364{
10365 // The assert is only to silence a false-positive in XCode Static Analysis.
10366 // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions).
10367 IM_ASSERT(GImGui != NULL);
10368 const float MOUSE_INVALID = -256000.0f;
10369 ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;
10370 return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;
10371}
10372
10373// [WILL OBSOLETE] This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid.
10375{
10376 ImGuiContext& g = *GImGui;
10377 for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
10378 if (g.IO.MouseDown[n])
10379 return true;
10380 return false;
10381}
10382
10383// Return the delta from the initial clicking position while the mouse button is clicked or was just released.
10384// This is locked and return 0.0f until the mouse moves past a distance threshold at least once.
10385// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window.
10387{
10388 ImGuiContext& g = *GImGui;
10389 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10390 if (lock_threshold < 0.0f)
10391 lock_threshold = g.IO.MouseDragThreshold;
10392 if (g.IO.MouseDown[button] || g.IO.MouseReleased[button])
10393 if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
10395 return g.IO.MousePos - g.IO.MouseClickedPos[button];
10396 return ImVec2(0.0f, 0.0f);
10397}
10398
10400{
10401 ImGuiContext& g = *GImGui;
10402 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
10403 // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
10404 g.IO.MouseClickedPos[button] = g.IO.MousePos;
10405}
10406
10407// Get desired mouse cursor shape.
10408// Important: this is meant to be used by a platform backend, it is reset in ImGui::NewFrame(),
10409// updated during the frame, and locked in EndFrame()/Render().
10410// If you use software rendering by setting io.MouseDrawCursor then Dear ImGui will render those for you
10412{
10413 ImGuiContext& g = *GImGui;
10414 return g.MouseCursor;
10415}
10416
10417// We intentionally accept values of ImGuiMouseCursor that are outside our bounds, in case users needs to hack-in a custom cursor value.
10418// Custom cursors may be handled by custom backends. If you are using a standard backend and want to hack in a custom cursor, you may
10419// handle it before the backend _NewFrame() call and temporarily set ImGuiConfigFlags_NoMouseCursorChange during the backend _NewFrame() call.
10421{
10422 ImGuiContext& g = *GImGui;
10423 g.MouseCursor = cursor_type;
10424}
10425
10426static void UpdateAliasKey(ImGuiKey key, bool v, float analog_value)
10427{
10429 ImGuiKeyData* key_data = ImGui::GetKeyData(key);
10430 key_data->Down = v;
10431 key_data->AnalogValue = analog_value;
10432}
10433
10434// [Internal] Do not use directly
10436{
10437 ImGuiKeyChord mods = 0;
10440 if (ImGui::IsKeyDown(ImGuiMod_Alt)) { mods |= ImGuiMod_Alt; }
10442 return mods;
10443}
10444
10446{
10447 ImGuiContext& g = *GImGui;
10448 ImGuiIO& io = g.IO;
10449
10451 io.ClearInputKeys();
10452
10453 // Update aliases
10454 for (int n = 0; n < ImGuiMouseButton_COUNT; n++)
10455 UpdateAliasKey(MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] ? 1.0f : 0.0f);
10458
10459 // Synchronize io.KeyMods and io.KeyCtrl/io.KeyShift/etc. values.
10460 // - New backends (1.87+): send io.AddKeyEvent(ImGuiMod_XXX) -> -> (here) deriving io.KeyMods + io.KeyXXX from key array.
10461 // - Legacy backends: set io.KeyXXX bools -> (above) set key array from io.KeyXXX -> (here) deriving io.KeyMods + io.KeyXXX from key array.
10462 // So with legacy backends the 4 values will do a unnecessary back-and-forth but it makes the code simpler and future facing.
10463 const ImGuiKeyChord prev_key_mods = io.KeyMods;
10465 io.KeyCtrl = (io.KeyMods & ImGuiMod_Ctrl) != 0;
10466 io.KeyShift = (io.KeyMods & ImGuiMod_Shift) != 0;
10467 io.KeyAlt = (io.KeyMods & ImGuiMod_Alt) != 0;
10468 io.KeySuper = (io.KeyMods & ImGuiMod_Super) != 0;
10469 if (prev_key_mods != io.KeyMods)
10471 if (prev_key_mods != io.KeyMods && prev_key_mods == 0)
10473
10474 // Clear gamepad data if disabled
10476 for (int key = ImGuiKey_Gamepad_BEGIN; key < ImGuiKey_Gamepad_END; key++)
10477 {
10478 io.KeysData[key - ImGuiKey_NamedKey_BEGIN].Down = false;
10480 }
10481
10482 // Update keys
10483 for (int key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key++)
10484 {
10485 ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_NamedKey_BEGIN];
10486 key_data->DownDurationPrev = key_data->DownDuration;
10487 key_data->DownDuration = key_data->Down ? (key_data->DownDuration < 0.0f ? 0.0f : key_data->DownDuration + io.DeltaTime) : -1.0f;
10488 if (key_data->DownDuration == 0.0f)
10489 {
10490 if (IsKeyboardKey((ImGuiKey)key))
10494 }
10495 }
10496
10497 // Update keys/input owner (named keys only): one entry per key
10498 for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
10499 {
10500 ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_NamedKey_BEGIN];
10502 owner_data->OwnerCurr = owner_data->OwnerNext;
10503 if (!key_data->Down) // Important: ownership is released on the frame after a release. Ensure a 'MouseDown -> CloseWindow -> MouseUp' chain doesn't lead to someone else seeing the MouseUp.
10504 owner_data->OwnerNext = ImGuiKeyOwner_NoOwner;
10505 owner_data->LockThisFrame = owner_data->LockUntilRelease = owner_data->LockUntilRelease && key_data->Down; // Clear LockUntilRelease when key is not Down anymore
10506 }
10507
10508 // Update key routing (for e.g. shortcuts)
10510}
10511
10513{
10514 ImGuiContext& g = *GImGui;
10515 ImGuiIO& io = g.IO;
10516
10517 // Mouse Wheel swapping flag
10518 // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
10519 // - We avoid doing it on OSX as it the OS input layer handles this already.
10520 // - FIXME: However this means when running on OSX over Emscripten, Shift+WheelY will incur two swapping (1 in OS, 1 here), canceling the feature.
10521 // - FIXME: When we can distinguish e.g. touchpad scroll events from mouse ones, we'll set this accordingly based on input source.
10523
10524 // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)
10525 if (IsMousePosValid(&io.MousePos))
10527
10528 // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta
10530 io.MouseDelta = io.MousePos - io.MousePosPrev;
10531 else
10532 io.MouseDelta = ImVec2(0.0f, 0.0f);
10533
10534 // Update stationary timer.
10535 // FIXME: May need to rework again to have some tolerance for occasional small movement, while being functional on high-framerates.
10536 const float mouse_stationary_threshold = (io.MouseSource == ImGuiMouseSource_Mouse) ? 2.0f : 3.0f; // Slightly higher threshold for ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen, may need rework.
10537 const bool mouse_stationary = (ImLengthSqr(io.MouseDelta) <= mouse_stationary_threshold * mouse_stationary_threshold);
10538 g.MouseStationaryTimer = mouse_stationary ? (g.MouseStationaryTimer + io.DeltaTime) : 0.0f;
10539 //IMGUI_DEBUG_LOG("%.4f\n", g.MouseStationaryTimer);
10540
10541 // If mouse moved we re-enable mouse hovering in case it was disabled by keyboard/gamepad. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true.
10542 if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)
10543 g.NavHighlightItemUnderNav = false;
10544
10545 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
10546 {
10547 io.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f;
10548 io.MouseClickedCount[i] = 0; // Will be filled below
10549 io.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0f;
10550 if (io.MouseReleased[i])
10551 io.MouseReleasedTime[i] = g.Time;
10553 io.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0.0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f;
10554 if (io.MouseClicked[i])
10555 {
10556 bool is_repeated_click = false;
10557 if ((float)(g.Time - io.MouseClickedTime[i]) < io.MouseDoubleClickTime)
10558 {
10559 ImVec2 delta_from_click_pos = IsMousePosValid(&io.MousePos) ? (io.MousePos - io.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
10560 if (ImLengthSqr(delta_from_click_pos) < io.MouseDoubleClickMaxDist * io.MouseDoubleClickMaxDist)
10561 is_repeated_click = true;
10562 }
10563 if (is_repeated_click)
10564 io.MouseClickedLastCount[i]++;
10565 else
10566 io.MouseClickedLastCount[i] = 1;
10567 io.MouseClickedTime[i] = g.Time;
10568 io.MouseClickedPos[i] = io.MousePos;
10570 io.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f);
10571 io.MouseDragMaxDistanceSqr[i] = 0.0f;
10572 }
10573 else if (io.MouseDown[i])
10574 {
10575 // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold
10576 ImVec2 delta_from_click_pos = IsMousePosValid(&io.MousePos) ? (io.MousePos - io.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
10577 io.MouseDragMaxDistanceSqr[i] = ImMax(io.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos));
10578 io.MouseDragMaxDistanceAbs[i].x = ImMax(io.MouseDragMaxDistanceAbs[i].x, delta_from_click_pos.x < 0.0f ? -delta_from_click_pos.x : delta_from_click_pos.x);
10579 io.MouseDragMaxDistanceAbs[i].y = ImMax(io.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y);
10580 }
10581
10582 // We provide io.MouseDoubleClicked[] as a legacy service
10583 io.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2);
10584
10585 // Clicking any mouse button reactivate mouse hovering which may have been deactivated by keyboard/gamepad navigation
10586 if (io.MouseClicked[i])
10587 g.NavHighlightItemUnderNav = false;
10588 }
10589}
10590
10591static void LockWheelingWindow(ImGuiWindow* window, float wheel_amount)
10592{
10593 ImGuiContext& g = *GImGui;
10594 if (window)
10596 else
10598 if (g.WheelingWindow == window)
10599 return;
10600 IMGUI_DEBUG_LOG_IO("[io] LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL");
10601 g.WheelingWindow = window;
10603 if (window == NULL)
10604 {
10606 g.WheelingAxisAvg = ImVec2(0.0f, 0.0f);
10607 }
10608}
10609
10611{
10612 // For each axis, find window in the hierarchy that may want to use scrolling
10613 ImGuiContext& g = *GImGui;
10614 ImGuiWindow* windows[2] = { NULL, NULL };
10615 for (int axis = 0; axis < 2; axis++)
10616 if (wheel[axis] != 0.0f)
10617 for (ImGuiWindow* window = windows[axis] = g.HoveredWindow; window->Flags & ImGuiWindowFlags_ChildWindow; window = windows[axis] = window->ParentWindow)
10618 {
10619 // Bubble up into parent window if:
10620 // - a child window doesn't allow any scrolling.
10621 // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag.
10623 const bool has_scrolling = (window->ScrollMax[axis] != 0.0f);
10624 const bool inputs_disabled = (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs);
10625 //const bool scrolling_past_limits = (wheel_v < 0.0f) ? (window->Scroll[axis] <= 0.0f) : (window->Scroll[axis] >= window->ScrollMax[axis]);
10626 if (has_scrolling && !inputs_disabled) // && !scrolling_past_limits)
10627 break; // select this window
10628 }
10629 if (windows[0] == NULL && windows[1] == NULL)
10630 return NULL;
10631
10632 // If there's only one window or only one axis then there's no ambiguity
10633 if (windows[0] == windows[1] || windows[0] == NULL || windows[1] == NULL)
10634 return windows[1] ? windows[1] : windows[0];
10635
10636 // If candidate are different windows we need to decide which one to prioritize
10637 // - First frame: only find a winner if one axis is zero.
10638 // - Subsequent frames: only find a winner when one is more than the other.
10639 if (g.WheelingWindowStartFrame == -1)
10641 if ((g.WheelingWindowStartFrame == g.FrameCount && wheel.x != 0.0f && wheel.y != 0.0f) || (g.WheelingAxisAvg.x == g.WheelingAxisAvg.y))
10642 {
10644 return NULL;
10645 }
10646 return (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? windows[0] : windows[1];
10647}
10648
10649// Called by NewFrame()
10651{
10652 // Reset the locked window if we move the mouse or after the timer elapses.
10653 // FIXME: Ideally we could refactor to have one timer for "changing window w/ same axis" and a shorter timer for "changing window or axis w/ other axis" (#3795)
10654 ImGuiContext& g = *GImGui;
10655 if (g.WheelingWindow != NULL)
10656 {
10660 if (g.WheelingWindowReleaseTimer <= 0.0f)
10661 LockWheelingWindow(NULL, 0.0f);
10662 }
10663
10664 ImVec2 wheel;
10667
10668 //IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y);
10669 ImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
10670 if (!mouse_window || mouse_window->Collapsed)
10671 return;
10672
10673 // Zoom / Scale window
10674 // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
10675 if (wheel.y != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
10676 {
10677 LockWheelingWindow(mouse_window, wheel.y);
10678 ImGuiWindow* window = mouse_window;
10679 const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
10680 const float scale = new_font_scale / window->FontWindowScale;
10681 window->FontWindowScale = new_font_scale;
10682 if (window == window->RootWindow)
10683 {
10684 const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
10685 SetWindowPos(window, window->Pos + offset, 0);
10686 window->Size = ImTrunc(window->Size * scale);
10687 window->SizeFull = ImTrunc(window->SizeFull * scale);
10688 }
10689 return;
10690 }
10691 if (g.IO.KeyCtrl)
10692 return;
10693
10694 // Mouse wheel scrolling
10695 // Read about io.MouseWheelRequestAxisSwap and its issue on Mac+Emscripten in UpdateMouseInputs()
10697 wheel = ImVec2(wheel.y, 0.0f);
10698
10699 // Maintain a rough average of moving magnitude on both axes
10700 // FIXME: should by based on wall clock time rather than frame-counter
10703
10704 // In the rare situation where FindBestWheelingWindow() had to defer first frame of wheeling due to ambiguous main axis, reinject it now.
10706 g.WheelingWindowWheelRemainder = ImVec2(0.0f, 0.0f);
10707 if (wheel.x == 0.0f && wheel.y == 0.0f)
10708 return;
10709
10710 // Mouse wheel scrolling: find target and apply
10711 // - don't renew lock if axis doesn't apply on the window.
10712 // - select a main axis when both axes are being moved.
10713 if (ImGuiWindow* window = (g.WheelingWindow ? g.WheelingWindow : FindBestWheelingWindow(wheel)))
10714 if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
10715 {
10716 bool do_scroll[2] = { wheel.x != 0.0f && window->ScrollMax.x != 0.0f, wheel.y != 0.0f && window->ScrollMax.y != 0.0f };
10717 if (do_scroll[ImGuiAxis_X] && do_scroll[ImGuiAxis_Y])
10718 do_scroll[(g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? ImGuiAxis_Y : ImGuiAxis_X] = false;
10719 if (do_scroll[ImGuiAxis_X])
10720 {
10721 LockWheelingWindow(window, wheel.x);
10722 float max_step = window->InnerRect.GetWidth() * 0.67f;
10723 float scroll_step = ImTrunc(ImMin(2 * window->FontRefSize, max_step));
10724 SetScrollX(window, window->Scroll.x - wheel.x * scroll_step);
10726 }
10727 if (do_scroll[ImGuiAxis_Y])
10728 {
10729 LockWheelingWindow(window, wheel.y);
10730 float max_step = window->InnerRect.GetHeight() * 0.67f;
10731 float scroll_step = ImTrunc(ImMin(5 * window->FontRefSize, max_step));
10732 SetScrollY(window, window->Scroll.y - wheel.y * scroll_step);
10734 }
10735 }
10736}
10737
10738void ImGui::SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard)
10739{
10740 ImGuiContext& g = *GImGui;
10741 g.WantCaptureKeyboardNextFrame = want_capture_keyboard ? 1 : 0;
10742}
10743
10744void ImGui::SetNextFrameWantCaptureMouse(bool want_capture_mouse)
10745{
10746 ImGuiContext& g = *GImGui;
10747 g.WantCaptureMouseNextFrame = want_capture_mouse ? 1 : 0;
10748}
10749
10750#ifndef IMGUI_DISABLE_DEBUG_TOOLS
10751static const char* GetInputSourceName(ImGuiInputSource source)
10752{
10753 const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad" };
10754 IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT);
10755 return input_source_names[source];
10756}
10757static const char* GetMouseSourceName(ImGuiMouseSource source)
10758{
10759 const char* mouse_source_names[] = { "Mouse", "TouchScreen", "Pen" };
10760 IM_ASSERT(IM_ARRAYSIZE(mouse_source_names) == ImGuiMouseSource_COUNT && source >= 0 && source < ImGuiMouseSource_COUNT);
10761 return mouse_source_names[source];
10762}
10763static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e)
10764{
10765 ImGuiContext& g = *GImGui;
10766 if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MousePos.MouseSource)); return; }
10767 if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseButton.MouseSource)); return; }
10768 if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseWheel (%.3f, %.3f) (%s)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; }
10769 if (e->Type == ImGuiInputEventType_MouseViewport){IMGUI_DEBUG_LOG_IO("[io] %s: MouseViewport (0x%08X)\n", prefix, e->MouseViewport.HoveredViewportID); return; }
10770 if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("[io] %s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; }
10771 if (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO("[io] %s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; }
10772 if (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO("[io] %s: AppFocused %d\n", prefix, e->AppFocused.Focused); return; }
10773}
10774#endif
10775
10776// Process input queue
10777// We always call this with the value of 'bool g.IO.ConfigInputTrickleEventQueue'.
10778// - trickle_fast_inputs = false : process all events, turn into flattened input state (e.g. successive down/up/down/up will be lost)
10779// - trickle_fast_inputs = true : process as many events as possible (successive down/up/down/up will be trickled over several frames so nothing is lost) (new feature in 1.87)
10780void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
10781{
10782 ImGuiContext& g = *GImGui;
10783 ImGuiIO& io = g.IO;
10784
10785 // Only trickle chars<>key when working with InputText()
10786 // FIXME: InputText() could parse event trail?
10787 // FIXME: Could specialize chars<>keys trickling rules for control keys (those not typically associated to characters)
10788 const bool trickle_interleaved_nonchar_keys_and_text = (trickle_fast_inputs && g.WantTextInputNextFrame == 1);
10789
10790 bool mouse_moved = false, mouse_wheeled = false, key_changed = false, key_changed_nonchar = false, text_inputted = false;
10791 int mouse_button_changed = 0x00;
10792 ImBitArray<ImGuiKey_NamedKey_COUNT> key_changed_mask;
10793
10794 int event_n = 0;
10795 for (; event_n < g.InputEventsQueue.Size; event_n++)
10796 {
10797 ImGuiInputEvent* e = &g.InputEventsQueue[event_n];
10799 {
10800 if (g.IO.WantSetMousePos)
10801 continue;
10802 // Trickling Rule: Stop processing queued events if we already handled a mouse button change
10803 ImVec2 event_pos(e->MousePos.PosX, e->MousePos.PosY);
10804 if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted))
10805 break;
10806 io.MousePos = event_pos;
10808 mouse_moved = true;
10809 }
10811 {
10812 // Trickling Rule: Stop processing queued events if we got multiple action on the same button
10813 const ImGuiMouseButton button = e->MouseButton.Button;
10814 IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT);
10815 if (trickle_fast_inputs && ((mouse_button_changed & (1 << button)) || mouse_wheeled))
10816 break;
10817 if (trickle_fast_inputs && e->MouseButton.MouseSource == ImGuiMouseSource_TouchScreen && mouse_moved) // #2702: TouchScreen have no initial hover.
10818 break;
10819 io.MouseDown[button] = e->MouseButton.Down;
10821 mouse_button_changed |= (1 << button);
10822 }
10823 else if (e->Type == ImGuiInputEventType_MouseWheel)
10824 {
10825 // Trickling Rule: Stop processing queued events if we got multiple action on the event
10826 if (trickle_fast_inputs && (mouse_moved || mouse_button_changed != 0))
10827 break;
10828 io.MouseWheelH += e->MouseWheel.WheelX;
10829 io.MouseWheel += e->MouseWheel.WheelY;
10831 mouse_wheeled = true;
10832 }
10834 {
10836 }
10837 else if (e->Type == ImGuiInputEventType_Key)
10838 {
10839 // Trickling Rule: Stop processing queued events if we got multiple action on the same button
10841 continue;
10842 ImGuiKey key = e->Key.Key;
10843 IM_ASSERT(key != ImGuiKey_None);
10844 ImGuiKeyData* key_data = GetKeyData(key);
10845 const int key_data_index = (int)(key_data - g.IO.KeysData);
10846 if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || mouse_button_changed != 0))
10847 break;
10848
10849 const bool key_is_potentially_for_char_input = IsKeyChordPotentiallyCharInput(GetMergedModsFromKeys() | key);
10850 if (trickle_interleaved_nonchar_keys_and_text && (text_inputted && !key_is_potentially_for_char_input))
10851 break;
10852
10853 if (key_data->Down != e->Key.Down) // Analog change only do not trigger this, so it won't block e.g. further mouse pos events testing key_changed.
10854 {
10855 key_changed = true;
10856 key_changed_mask.SetBit(key_data_index);
10857 if (trickle_interleaved_nonchar_keys_and_text && !key_is_potentially_for_char_input)
10858 key_changed_nonchar = true;
10859 }
10860
10861 key_data->Down = e->Key.Down;
10862 key_data->AnalogValue = e->Key.AnalogValue;
10863 }
10864 else if (e->Type == ImGuiInputEventType_Text)
10865 {
10867 continue;
10868 // Trickling Rule: Stop processing queued events if keys/mouse have been interacted with
10869 if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_moved || mouse_wheeled))
10870 break;
10871 if (trickle_interleaved_nonchar_keys_and_text && key_changed_nonchar)
10872 break;
10873 unsigned int c = e->Text.Char;
10875 if (trickle_interleaved_nonchar_keys_and_text)
10876 text_inputted = true;
10877 }
10878 else if (e->Type == ImGuiInputEventType_Focus)
10879 {
10880 // We intentionally overwrite this and process in NewFrame(), in order to give a chance
10881 // to multi-viewports backends to queue AddFocusEvent(false) + AddFocusEvent(true) in same frame.
10882 const bool focus_lost = !e->AppFocused.Focused;
10883 io.AppFocusLost = focus_lost;
10884 }
10885 else
10886 {
10887 IM_ASSERT(0 && "Unknown event!");
10888 }
10889 }
10890
10891 // Record trail (for domain-specific applications wanting to access a precise trail)
10892 //if (event_n != 0) IMGUI_DEBUG_LOG_IO("Processed: %d / Remaining: %d\n", event_n, g.InputEventsQueue.Size - event_n);
10893 for (int n = 0; n < event_n; n++)
10895
10896 // [DEBUG]
10897#ifndef IMGUI_DISABLE_DEBUG_TOOLS
10898 if (event_n != 0 && (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO))
10899 for (int n = 0; n < g.InputEventsQueue.Size; n++)
10900 DebugPrintInputEvent(n < event_n ? "Processed" : "Remaining", &g.InputEventsQueue[n]);
10901#endif
10902
10903 // Remaining events will be processed on the next frame
10904 if (event_n == g.InputEventsQueue.Size)
10906 else
10908
10909 // Clear buttons state when focus is lost
10910 // - this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't trigger the Alt menu toggle.
10911 // - we clear in EndFrame() and not now in order allow application/user code polling this flag
10912 // (e.g. custom backend may want to clear additional data, custom widgets may want to react with a "canceling" event).
10913 if (g.IO.AppFocusLost)
10914 {
10915 g.IO.ClearInputKeys();
10916 g.IO.ClearInputMouse();
10917 }
10918}
10919
10921{
10922 if (!IsNamedKeyOrMod(key))
10923 return ImGuiKeyOwner_NoOwner;
10924
10925 ImGuiContext& g = *GImGui;
10926 ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
10927 ImGuiID owner_id = owner_data->OwnerCurr;
10928
10929 if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any)
10931 return ImGuiKeyOwner_NoOwner;
10932
10933 return owner_id;
10934}
10935
10936// TestKeyOwner(..., ID) : (owner == None || owner == ID)
10937// TestKeyOwner(..., None) : (owner == None)
10938// TestKeyOwner(..., Any) : no owner test
10939// All paths are also testing for key not being locked, for the rare cases that key have been locked with using ImGuiInputFlags_LockXXX flags.
10941{
10942 if (!IsNamedKeyOrMod(key))
10943 return true;
10944
10945 ImGuiContext& g = *GImGui;
10946 if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any)
10948 return false;
10949
10950 ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
10951 if (owner_id == ImGuiKeyOwner_Any)
10952 return (owner_data->LockThisFrame == false);
10953
10954 // Note: SetKeyOwner() sets OwnerCurr. It is not strictly required for most mouse routing overlap (because of ActiveId/HoveredId
10955 // are acting as filter before this has a chance to filter), but sane as soon as user tries to look into things.
10956 // Setting OwnerCurr in SetKeyOwner() is more consistent than testing OwnerNext here: would be inconsistent with getter and other functions.
10957 if (owner_data->OwnerCurr != owner_id)
10958 {
10959 if (owner_data->LockThisFrame)
10960 return false;
10961 if (owner_data->OwnerCurr != ImGuiKeyOwner_NoOwner)
10962 return false;
10963 }
10964
10965 return true;
10966}
10967
10968// _LockXXX flags are useful to lock keys away from code which is not input-owner aware.
10969// When using _LockXXX flags, you can use ImGuiKeyOwner_Any to lock keys from everyone.
10970// - SetKeyOwner(..., None) : clears owner
10971// - SetKeyOwner(..., Any, !Lock) : illegal (assert)
10972// - SetKeyOwner(..., Any or None, Lock) : set lock
10974{
10975 ImGuiContext& g = *GImGui;
10976 IM_ASSERT(IsNamedKeyOrMod(key) && (owner_id != ImGuiKeyOwner_Any || (flags & (ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease)))); // Can only use _Any with _LockXXX flags (to eat a key away without an ID to retrieve it)
10977 IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetKeyOwner) == 0); // Passing flags not supported by this function!
10978 //IMGUI_DEBUG_LOG("SetKeyOwner(%s, owner_id=0x%08X, flags=%08X)\n", GetKeyName(key), owner_id, flags);
10979
10980 ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
10981 owner_data->OwnerCurr = owner_data->OwnerNext = owner_id;
10982
10983 // We cannot lock by default as it would likely break lots of legacy code.
10984 // In the case of using LockUntilRelease while key is not down we still lock during the frame (no key_data->Down test)
10985 owner_data->LockUntilRelease = (flags & ImGuiInputFlags_LockUntilRelease) != 0;
10986 owner_data->LockThisFrame = (flags & ImGuiInputFlags_LockThisFrame) != 0 || (owner_data->LockUntilRelease);
10987}
10988
10989// Rarely used helper
10991{
10992 if (key_chord & ImGuiMod_Ctrl) { SetKeyOwner(ImGuiMod_Ctrl, owner_id, flags); }
10993 if (key_chord & ImGuiMod_Shift) { SetKeyOwner(ImGuiMod_Shift, owner_id, flags); }
10994 if (key_chord & ImGuiMod_Alt) { SetKeyOwner(ImGuiMod_Alt, owner_id, flags); }
10995 if (key_chord & ImGuiMod_Super) { SetKeyOwner(ImGuiMod_Super, owner_id, flags); }
10996 if (key_chord & ~ImGuiMod_Mask_) { SetKeyOwner((ImGuiKey)(key_chord & ~ImGuiMod_Mask_), owner_id, flags); }
10997}
10998
10999// This is more or less equivalent to:
11000// if (IsItemHovered() || IsItemActive())
11001// SetKeyOwner(key, GetItemID());
11002// Extensive uses of that (e.g. many calls for a single item) may want to manually perform the tests once and then call SetKeyOwner() multiple times.
11003// More advanced usage scenarios may want to call SetKeyOwner() manually based on different condition.
11004// Worth noting is that only one item can be hovered and only one item can be active, therefore this usage pattern doesn't need to bother with routing and priority.
11006{
11007 ImGuiContext& g = *GImGui;
11008 ImGuiID id = g.LastItemData.ID;
11009 if (id == 0 || (g.HoveredId != id && g.ActiveId != id))
11010 return;
11011 if ((flags & ImGuiInputFlags_CondMask_) == 0)
11013 if ((g.HoveredId == id && (flags & ImGuiInputFlags_CondHovered)) || (g.ActiveId == id && (flags & ImGuiInputFlags_CondActive)))
11014 {
11015 IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetItemKeyOwner) == 0); // Passing flags not supported by this function!
11016 SetKeyOwner(key, id, flags & ~ImGuiInputFlags_CondMask_);
11017 }
11018}
11019
11021{
11023}
11024
11025// This is the only public API until we expose owner_id versions of the API as replacements.
11027{
11029}
11030
11031// This is equivalent to comparing KeyMods + doing a IsKeyPressed()
11033{
11034 ImGuiContext& g = *GImGui;
11035 key_chord = FixupKeyChord(key_chord);
11036 ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);
11037 if (g.IO.KeyMods != mods)
11038 return false;
11039
11040 // Special storage location for mods
11041 ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
11042 if (key == ImGuiKey_None)
11043 key = ConvertSingleModFlagToKey(mods);
11044 if (!IsKeyPressed(key, (flags & ImGuiInputFlags_RepeatMask_), owner_id))
11045 return false;
11046 return true;
11047}
11048
11050{
11051 ImGuiContext& g = *GImGui;
11053 g.NextItemData.Shortcut = key_chord;
11054 g.NextItemData.ShortcutFlags = flags;
11055}
11056
11057// Called from within ItemAdd: at this point we can read from NextItemData and write to LastItemData
11059{
11060 ImGuiContext& g = *GImGui;
11062 IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetNextItemShortcut) == 0); // Passing flags not supported by SetNextItemShortcut()!
11063
11065 return;
11066 if (flags & ImGuiInputFlags_Tooltip)
11067 {
11070 }
11072 return;
11073
11074 // FIXME: Generalize Activation queue?
11075 g.NavActivateId = id; // Will effectively disable clipping.
11077 //if (g.ActiveId == 0 || g.ActiveId == id)
11080}
11081
11083{
11084 return Shortcut(key_chord, flags, ImGuiKeyOwner_Any);
11085}
11086
11088{
11089 ImGuiContext& g = *GImGui;
11090 //IMGUI_DEBUG_LOG("Shortcut(%s, flags=%X, owner_id=0x%08X)\n", GetKeyChordName(key_chord, g.TempBuffer.Data, g.TempBuffer.Size), flags, owner_id);
11091
11092 // When using (owner_id == 0/Any): SetShortcutRouting() will use CurrentFocusScopeId and filter with this, so IsKeyPressed() is fine with he 0/Any.
11093 if ((flags & ImGuiInputFlags_RouteTypeMask_) == 0)
11095
11096 // Using 'owner_id == ImGuiKeyOwner_Any/0': auto-assign an owner based on current focus scope (each window has its focus scope by default)
11097 // Effectively makes Shortcut() always input-owner aware.
11098 if (owner_id == ImGuiKeyOwner_Any || owner_id == ImGuiKeyOwner_NoOwner)
11099 owner_id = GetRoutingIdFromOwnerId(owner_id);
11100
11102 return false;
11103
11104 // Submit route
11105 if (!SetShortcutRouting(key_chord, flags, owner_id))
11106 return false;
11107
11108 // Default repeat behavior for Shortcut()
11109 // So e.g. pressing Ctrl+W and releasing Ctrl while holding W will not trigger the W shortcut.
11110 if ((flags & ImGuiInputFlags_Repeat) != 0 && (flags & ImGuiInputFlags_RepeatUntilMask_) == 0)
11112
11113 if (!IsKeyChordPressed(key_chord, flags, owner_id))
11114 return false;
11115
11116 // Claim mods during the press
11117 SetKeyOwnersForKeyChord(key_chord & ImGuiMod_Mask_, owner_id);
11118
11119 IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByShortcut) == 0); // Passing flags not supported by this function!
11120 return true;
11121}
11122
11123//-----------------------------------------------------------------------------
11124// [SECTION] ERROR CHECKING, STATE RECOVERY
11125//-----------------------------------------------------------------------------
11126// - DebugCheckVersionAndDataLayout() (called via IMGUI_CHECKVERSION() macros)
11127// - ErrorCheckUsingSetCursorPosToExtendParentBoundaries()
11128// - ErrorCheckNewFrameSanityChecks()
11129// - ErrorCheckEndFrameSanityChecks()
11130// - ErrorRecoveryStoreState()
11131// - ErrorRecoveryTryToRecoverState()
11132// - ErrorRecoveryTryToRecoverWindowState()
11133// - ErrorLog()
11134//-----------------------------------------------------------------------------
11135
11136// Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues.
11137// Called by IMGUI_CHECKVERSION().
11138// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
11139// If this triggers you have mismatched headers and compiled code versions.
11140// - It could be because of a build issue (using new headers with old compiled code)
11141// - It could be because of mismatched configuration #define, compilation settings, packing pragma etc.
11142// THE CONFIGURATION SETTINGS MENTIONED IN imconfig.h MUST BE SET FOR ALL COMPILATION UNITS INVOLVED WITH DEAR IMGUI.
11143// Which is why it is required you put them in your imconfig file (and NOT only before including imgui.h).
11144// Otherwise it is possible that different compilation units would see different structure layout.
11145// If you don't want to modify imconfig.h you can use the IMGUI_USER_CONFIG define to change filename.
11146bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx)
11147{
11148 bool error = false;
11149 if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); }
11150 if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); }
11151 if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); }
11152 if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); }
11153 if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); }
11154 if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); }
11155 if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); }
11156 return !error;
11157}
11158
11159// Until 1.89 (August 2022, IMGUI_VERSION_NUM < 18814) it was legal to use SetCursorPos()/SetCursorScreenPos()
11160// to extend contents size of our parent container (e.g. window contents size, which is used for auto-resizing
11161// windows, table column contents size used for auto-resizing columns, group size).
11162// This was causing issues and ambiguities and we needed to retire that.
11163// From 1.89, extending contents size boundaries REQUIRES AN ITEM TO BE SUBMITTED.
11164//
11165// Previously this would make the window content size ~200x200:
11166// Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); // NOT OK ANYMORE
11167// Instead, please submit an item:
11168// Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End(); // OK
11169// Alternative:
11170// Begin(...) + Dummy(ImVec2(200,200)) + End(); // OK
11171//
11172// The assert below detects when the _last_ call in a window was a SetCursorPos() not followed by an Item,
11173// and with a position that would grow the parent contents size.
11174//
11175// Advanced:
11176// - For reference, old logic was causing issues because it meant that SetCursorScreenPos(GetCursorScreenPos())
11177// had a side-effect on layout! In particular this caused problem to compute group boundaries.
11178// e.g. BeginGroup() + SomeItem() + SetCursorScreenPos(GetCursorScreenPos()) + EndGroup() would cause the
11179// group to be taller because auto-sizing generally adds padding on bottom and right side.
11180// - While this code is a little twisted, no-one would expect SetXXX(GetXXX()) to have a side-effect.
11181// Using vertical alignment patterns would frequently trigger this sorts of issue.
11182// - See https://github.com/ocornut/imgui/issues/5548 for more details.
11184{
11185 ImGuiContext& g = *GImGui;
11186 ImGuiWindow* window = g.CurrentWindow;
11187 IM_ASSERT(window->DC.IsSetPos);
11188 window->DC.IsSetPos = false;
11189 if (window->DC.CursorPos.x <= window->DC.CursorMaxPos.x && window->DC.CursorPos.y <= window->DC.CursorMaxPos.y)
11190 return;
11191 if (window->SkipItems)
11192 return;
11193 IM_ASSERT_USER_ERROR(0, "Code uses SetCursorPos()/SetCursorScreenPos() to extend window/parent boundaries.\nPlease submit an item e.g. Dummy() afterwards in order to grow window/parent boundaries.");
11194
11195 // For reference, the old behavior was essentially:
11196 //window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
11197}
11198
11200{
11201 ImGuiContext& g = *GImGui;
11202
11203 // Check user IM_ASSERT macro
11204 // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means your assert macro is incorrectly defined!
11205 // If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block.
11206 // This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.)
11207 // #define IM_ASSERT(EXPR) if (SomeCode(EXPR)) SomeMoreCode(); // Wrong!
11208 // #define IM_ASSERT(EXPR) do { if (SomeCode(EXPR)) SomeMoreCode(); } while (0) // Correct!
11209 if (true) IM_ASSERT(1); else IM_ASSERT(0);
11210
11211 // Emscripten backends are often imprecise in their submission of DeltaTime. (#6114, #3644)
11212 // Ideally the Emscripten app/backend should aim to fix or smooth this value and avoid feeding zero, but we tolerate it.
11213#ifdef __EMSCRIPTEN__
11214 if (g.IO.DeltaTime <= 0.0f && g.FrameCount > 0)
11215 g.IO.DeltaTime = 0.00001f;
11216#endif
11217
11218 // Check user data
11219 // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument)
11221 IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!");
11222 IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
11223 IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!");
11224 IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!");
11225 IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!");
11226 IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations
11227 IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting!");
11228 IM_ASSERT(g.Style.WindowBorderHoverPadding > 0.0f && "Invalid style setting!"); // Required otherwise cannot resize from borders.
11232
11233 // Error handling: we do not accept 100% silent recovery! Please contact me if you feel this is getting in your way.
11234 if (g.IO.ConfigErrorRecovery)
11236
11237#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
11238 if (g.IO.FontGlobalScale > 1.0f)
11239 IM_ASSERT(g.Style.FontScaleMain == 1.0f && "Since 1.92: use style.FontScaleMain instead of g.IO.FontGlobalScale!");
11240
11241 // Remap legacy names
11243 {
11245 g.IO.ConfigFlags &= ~ImGuiConfigFlags_NavEnableSetMousePos;
11246 }
11248 {
11249 g.IO.ConfigNavCaptureKeyboard = false;
11250 g.IO.ConfigFlags &= ~ImGuiConfigFlags_NavNoCaptureKeyboard;
11251 }
11253 {
11254 g.IO.ConfigDpiScaleFonts = false;
11255 g.IO.ConfigFlags &= ~ImGuiConfigFlags_DpiEnableScaleFonts;
11256 }
11258 {
11259 g.IO.ConfigDpiScaleViewports = false;
11260 g.IO.ConfigFlags &= ~ImGuiConfigFlags_DpiEnableScaleViewports;
11261 }
11262
11263 // Remap legacy clipboard handlers (OBSOLETED in 1.91.1, August 2024)
11265 g.PlatformIO.Platform_GetClipboardTextFn = [](ImGuiContext* ctx) { return ctx->IO.GetClipboardTextFn(ctx->IO.ClipboardUserData); };
11267 g.PlatformIO.Platform_SetClipboardTextFn = [](ImGuiContext* ctx, const char* text) { return ctx->IO.SetClipboardTextFn(ctx->IO.ClipboardUserData, text); };
11268#endif
11269
11270 // Perform simple check: error if Docking or Viewport are enabled _exactly_ on frame 1 (instead of frame 0 or later), which is a common error leading to loss of .ini data.
11272 IM_ASSERT(0 && "Please set DockingEnable before the first call to NewFrame()! Otherwise you will lose your .ini settings!");
11274 IM_ASSERT(0 && "Please set ViewportsEnable before the first call to NewFrame()! Otherwise you will lose your .ini settings!");
11275
11276 // Perform simple checks: multi-viewport and platform windows support
11278 {
11280 {
11281 IM_ASSERT((g.FrameCount == 0 || g.FrameCount == g.FrameCountPlatformEnded) && "Forgot to call UpdatePlatformWindows() in main loop after EndFrame()? Check examples/ applications for reference.");
11282 IM_ASSERT(g.PlatformIO.Platform_CreateWindow != NULL && "Platform init didn't install handlers?");
11283 IM_ASSERT(g.PlatformIO.Platform_DestroyWindow != NULL && "Platform init didn't install handlers?");
11284 IM_ASSERT(g.PlatformIO.Platform_GetWindowPos != NULL && "Platform init didn't install handlers?");
11285 IM_ASSERT(g.PlatformIO.Platform_SetWindowPos != NULL && "Platform init didn't install handlers?");
11286 IM_ASSERT(g.PlatformIO.Platform_GetWindowSize != NULL && "Platform init didn't install handlers?");
11287 IM_ASSERT(g.PlatformIO.Platform_SetWindowSize != NULL && "Platform init didn't install handlers?");
11288 IM_ASSERT(g.PlatformIO.Monitors.Size > 0 && "Platform init didn't setup Monitors list?");
11289 IM_ASSERT((g.Viewports[0]->PlatformUserData != NULL || g.Viewports[0]->PlatformHandle != NULL) && "Platform init didn't setup main viewport.");
11291 IM_ASSERT(g.PlatformIO.Platform_SetWindowAlpha != NULL && "Platform_SetWindowAlpha handler is required to use io.ConfigDockingTransparent!");
11292 }
11293 else
11294 {
11295 // Disable feature, our backends do not support it
11296 g.IO.ConfigFlags &= ~ImGuiConfigFlags_ViewportsEnable;
11297 }
11298
11299 // Perform simple checks on platform monitor data + compute a total bounding box for quick early outs
11301 {
11302 IM_UNUSED(mon);
11303 IM_ASSERT(mon.MainSize.x > 0.0f && mon.MainSize.y > 0.0f && "Monitor main bounds not setup properly.");
11304 IM_ASSERT(ImRect(mon.MainPos, mon.MainPos + mon.MainSize).Contains(ImRect(mon.WorkPos, mon.WorkPos + mon.WorkSize)) && "Monitor work bounds not setup properly. If you don't have work area information, just copy MainPos/MainSize into them.");
11305 IM_ASSERT(mon.DpiScale > 0.0f && mon.DpiScale < 99.0f && "Monitor DpiScale is invalid."); // Typical correct values would be between 1.0f and 4.0f
11306 }
11307 }
11308}
11309
11311{
11312 // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame()
11313 // One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame().
11314 // It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will
11315 // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs.
11316 // We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0),
11317 // while still correctly asserting on mid-frame key press events.
11318 ImGuiContext& g = *GImGui;
11319 const ImGuiKeyChord key_mods = GetMergedModsFromKeys();
11320 IM_UNUSED(g);
11321 IM_UNUSED(key_mods);
11322 IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");
11323 IM_UNUSED(key_mods);
11324
11326 IM_ASSERT(g.CurrentWindowStack[0].Window->IsFallbackWindow);
11327}
11328
11329// Save current stack sizes. Called e.g. by NewFrame() and by Begin() but may be called for manual recovery.
11331{
11332 ImGuiContext& g = *GImGui;
11333 state_out->SizeOfWindowStack = (short)g.CurrentWindowStack.Size;
11334 state_out->SizeOfIDStack = (short)g.CurrentWindow->IDStack.Size;
11335 state_out->SizeOfTreeStack = (short)g.CurrentWindow->DC.TreeDepth; // NOT g.TreeNodeStack.Size which is a partial stack!
11336 state_out->SizeOfColorStack = (short)g.ColorStack.Size;
11337 state_out->SizeOfStyleVarStack = (short)g.StyleVarStack.Size;
11338 state_out->SizeOfFontStack = (short)g.FontStack.Size;
11339 state_out->SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size;
11340 state_out->SizeOfGroupStack = (short)g.GroupStack.Size;
11341 state_out->SizeOfItemFlagsStack = (short)g.ItemFlagsStack.Size;
11342 state_out->SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size;
11343 state_out->SizeOfDisabledStack = (short)g.DisabledStackSize;
11344}
11345
11346// Chosen name "Try to recover" over e.g. "Restore" to suggest this is not a 100% guaranteed recovery.
11347// Called by e.g. EndFrame() but may be called for manual recovery.
11348// Attempt to recover full window stack.
11350{
11351 // PVS-Studio V1044 is "Loop break conditions do not depend on the number of iterations"
11352 ImGuiContext& g = *GImGui;
11353 while (g.CurrentWindowStack.Size > state_in->SizeOfWindowStack) //-V1044
11354 {
11355 // Recap:
11356 // - Begin()/BeginChild() return false to indicate the window is collapsed or fully clipped.
11357 // - Always call a matching End() for each Begin() call, regardless of its return value!
11358 // - Begin/End and BeginChild/EndChild logic is KNOWN TO BE INCONSISTENT WITH ALL OTHER BEGIN/END FUNCTIONS.
11359 // - We will fix that in a future major update.
11360 ImGuiWindow* window = g.CurrentWindow;
11361 if (window->Flags & ImGuiWindowFlags_ChildWindow)
11362 {
11363 if (g.CurrentTable != NULL && g.CurrentTable->InnerWindow == g.CurrentWindow)
11364 {
11365 IM_ASSERT_USER_ERROR(0, "Missing EndTable()");
11366 EndTable();
11367 }
11368 else
11369 {
11370 IM_ASSERT_USER_ERROR(0, "Missing EndChild()");
11371 EndChild();
11372 }
11373 }
11374 else
11375 {
11376 IM_ASSERT_USER_ERROR(0, "Missing End()");
11377 End();
11378 }
11379 }
11380 if (g.CurrentWindowStack.Size == state_in->SizeOfWindowStack)
11382}
11383
11384// Called by e.g. End() but may be called for manual recovery.
11385// Read '// Error Handling [BETA]' block in imgui_internal.h for details.
11386// Attempt to recover from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls.
11388{
11389 ImGuiContext& g = *GImGui;
11390
11391 while (g.CurrentTable != NULL && g.CurrentTable->InnerWindow == g.CurrentWindow) //-V1044
11392 {
11393 IM_ASSERT_USER_ERROR(0, "Missing EndTable()");
11394 EndTable();
11395 }
11396
11397 ImGuiWindow* window = g.CurrentWindow;
11398
11399 // FIXME: Can't recover from inside BeginTabItem/EndTabItem yet.
11400 while (g.CurrentTabBar != NULL && g.CurrentTabBar->Window == window) //-V1044
11401 {
11402 IM_ASSERT_USER_ERROR(0, "Missing EndTabBar()");
11403 EndTabBar();
11404 }
11405 while (g.CurrentMultiSelect != NULL && g.CurrentMultiSelect->Storage->Window == window) //-V1044
11406 {
11407 IM_ASSERT_USER_ERROR(0, "Missing EndMultiSelect()");
11409 }
11410 if (window->DC.MenuBarAppending) //-V1044
11411 {
11412 IM_ASSERT_USER_ERROR(0, "Missing EndMenuBar()");
11413 EndMenuBar();
11414 }
11415 while (window->DC.TreeDepth > state_in->SizeOfTreeStack) //-V1044
11416 {
11417 IM_ASSERT_USER_ERROR(0, "Missing TreePop()");
11418 TreePop();
11419 }
11420 while (g.GroupStack.Size > state_in->SizeOfGroupStack) //-V1044
11421 {
11422 IM_ASSERT_USER_ERROR(0, "Missing EndGroup()");
11423 EndGroup();
11424 }
11425 IM_ASSERT(g.GroupStack.Size == state_in->SizeOfGroupStack);
11426 while (window->IDStack.Size > state_in->SizeOfIDStack) //-V1044
11427 {
11428 IM_ASSERT_USER_ERROR(0, "Missing PopID()");
11429 PopID();
11430 }
11431 while (g.DisabledStackSize > state_in->SizeOfDisabledStack) //-V1044
11432 {
11433 IM_ASSERT_USER_ERROR(0, "Missing EndDisabled()");
11435 EndDisabled();
11436 else
11437 {
11440 }
11441 }
11443 while (g.ColorStack.Size > state_in->SizeOfColorStack) //-V1044
11444 {
11445 IM_ASSERT_USER_ERROR(0, "Missing PopStyleColor()");
11446 PopStyleColor();
11447 }
11448 while (g.ItemFlagsStack.Size > state_in->SizeOfItemFlagsStack) //-V1044
11449 {
11450 IM_ASSERT_USER_ERROR(0, "Missing PopItemFlag()");
11451 PopItemFlag();
11452 }
11453 while (g.StyleVarStack.Size > state_in->SizeOfStyleVarStack) //-V1044
11454 {
11455 IM_ASSERT_USER_ERROR(0, "Missing PopStyleVar()");
11456 PopStyleVar();
11457 }
11458 while (g.FontStack.Size > state_in->SizeOfFontStack) //-V1044
11459 {
11460 IM_ASSERT_USER_ERROR(0, "Missing PopFont()");
11461 PopFont();
11462 }
11463 while (g.FocusScopeStack.Size > state_in->SizeOfFocusScopeStack) //-V1044
11464 {
11465 IM_ASSERT_USER_ERROR(0, "Missing PopFocusScope()");
11466 PopFocusScope();
11467 }
11468 //IM_ASSERT(g.FocusScopeStack.Size == state_in->SizeOfFocusScopeStack);
11469}
11470
11471bool ImGui::ErrorLog(const char* msg)
11472{
11473 ImGuiContext& g = *GImGui;
11474
11475 // Output to debug log
11476#ifndef IMGUI_DISABLE_DEBUG_TOOLS
11477 ImGuiWindow* window = g.CurrentWindow;
11478
11480 {
11481 if (g.ErrorFirst)
11482 IMGUI_DEBUG_LOG_ERROR("[imgui-error] (current settings: Assert=%d, Log=%d, Tooltip=%d)\n",
11484 IMGUI_DEBUG_LOG_ERROR("[imgui-error] In window '%s': %s\n", window ? window->Name : "NULL", msg);
11485 }
11486 g.ErrorFirst = false;
11487
11488 // Output to tooltip
11490 {
11492 {
11493 if (g.ErrorCountCurrentFrame < 20)
11494 {
11495 Text("In window '%s': %s", window ? window->Name : "NULL", msg);
11496 if (window && (!window->IsFallbackWindow || window->WasActive))
11497 GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 0, 0, 255));
11498 }
11499 if (g.ErrorCountCurrentFrame == 20)
11500 Text("(and more errors)");
11501 // EndFrame() will amend debug buttons to this window, after all errors have been submitted.
11503 }
11505 }
11506#endif
11507
11508 // Output to callback
11509 if (g.ErrorCallback != NULL)
11511
11512 // Return whether we should assert
11514}
11515
11517{
11518#ifndef IMGUI_DISABLE_DEBUG_TOOLS
11519 ImGuiContext& g = *GImGui;
11520 if (g.DebugDrawIdConflictsId != 0 && g.IO.KeyCtrl == false)
11523 {
11524 Text("Programmer error: %d visible items with conflicting ID!", g.DebugDrawIdConflictsCount);
11525 BulletText("Code should use PushID()/PopID() in loops, or append \"##xx\" to same-label identifiers!");
11526 BulletText("Empty label e.g. Button(\"\") == same ID as parent widget/node. Use Button(\"##xx\") instead!");
11527 //BulletText("Code intending to use duplicate ID may use e.g. PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag()"); // Not making this too visible for fear of it being abused.
11528 BulletText("Set io.ConfigDebugHighlightIdConflicts=false to disable this warning in non-programmers builds.");
11529 Separator();
11531 {
11532 Text("(Hold CTRL to: use ");
11533 SameLine(0.0f, 0.0f);
11534 if (SmallButton("Item Picker"))
11536 SameLine(0.0f, 0.0f);
11537 Text(" to break in item call-stack, or ");
11538 }
11539 else
11540 {
11541 Text("(Hold CTRL to ");
11542 }
11543 SameLine(0.0f, 0.0f);
11544 if (SmallButton("Open FAQ->About ID Stack System") && g.PlatformIO.Platform_OpenInShellFn != NULL)
11545 g.PlatformIO.Platform_OpenInShellFn(&g, "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#qa-usage");
11546 SameLine(0.0f, 0.0f);
11547 Text(")");
11549 }
11550
11551 if (g.ErrorCountCurrentFrame > 0 && BeginErrorTooltip()) // Amend at end of frame
11552 {
11553 Separator();
11554 Text("(Hold CTRL to:");
11555 SameLine();
11556 if (SmallButton("Enable Asserts"))
11558 //SameLine();
11559 //if (SmallButton("Hide Error Tooltips"))
11560 // g.IO.ConfigErrorRecoveryEnableTooltip = false; // Too dangerous
11561 SameLine(0, 0);
11562 Text(")");
11564 }
11565#endif
11566}
11567
11568// Pseudo-tooltip. Follow mouse until CTRL is held. When CTRL is held we lock position, allowing to click it.
11570{
11571 ImGuiContext& g = *GImGui;
11572 ImGuiWindow* window = FindWindowByName("##Tooltip_Error");
11573 const bool use_locked_pos = (g.IO.KeyCtrl && window && window->WasActive);
11574 PushStyleColor(ImGuiCol_PopupBg, ImLerp(g.Style.Colors[ImGuiCol_PopupBg], ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 0.15f));
11575 if (use_locked_pos)
11578 PopStyleColor();
11579 if (is_visible && g.CurrentWindow->BeginCount == 1)
11580 {
11581 SeparatorText("MESSAGE FROM DEAR IMGUI");
11585 }
11586 else if (!is_visible)
11587 {
11588 End();
11589 }
11590 return is_visible;
11591}
11592
11594{
11595 End();
11596}
11597
11598//-----------------------------------------------------------------------------
11599// [SECTION] ITEM SUBMISSION
11600//-----------------------------------------------------------------------------
11601// - KeepAliveID()
11602// - ItemAdd()
11603//-----------------------------------------------------------------------------
11604
11605// Code not using ItemAdd() may need to call this manually otherwise ActiveId will be cleared. In IMGUI_VERSION_NUM < 18717 this was called by GetID().
11607{
11608 ImGuiContext& g = *GImGui;
11609 if (g.ActiveId == id)
11610 g.ActiveIdIsAlive = id;
11611 if (g.DeactivatedItemData.ID == id)
11613}
11614
11615// Declare item bounding box for clipping and interaction.
11616// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
11617// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction.
11618// THIS IS IN THE PERFORMANCE CRITICAL PATH (UNTIL THE CLIPPING TEST AND EARLY-RETURN)
11620bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemFlags extra_flags)
11621{
11622 ImGuiContext& g = *GImGui;
11623 ImGuiWindow* window = g.CurrentWindow;
11624
11625 // Set item data
11626 // (DisplayRect is left untouched, made valid when ImGuiItemStatusFlags_HasDisplayRect is set)
11627 g.LastItemData.ID = id;
11628 g.LastItemData.Rect = bb;
11629 g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb;
11632 // Note: we don't copy 'g.NextItemData.SelectionUserData' to an hypothetical g.LastItemData.SelectionUserData: since the former is not cleared.
11633
11634 if (id != 0)
11635 {
11636 KeepAliveID(id);
11637
11638 // Directional navigation processing
11639 // Runs prior to clipping early-out
11640 // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
11641 // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
11642 // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
11643 // thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
11644 // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
11645 // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
11646 // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
11647 // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
11649 {
11650 // FIMXE-NAV: investigate changing the window tests into a simple 'if (g.NavFocusScopeId == g.CurrentFocusScopeId)' test.
11651 window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
11652 if (g.NavId == id || g.NavAnyRequest)
11654 if (window == g.NavWindow || ((window->ChildFlags | g.NavWindow->ChildFlags) & ImGuiChildFlags_NavFlattened))
11656 }
11657
11660 }
11661
11662 // Lightweight clear of SetNextItemXXX data.
11665
11666#ifdef IMGUI_ENABLE_TEST_ENGINE
11667 if (id != 0)
11669#endif
11670
11671 // Clipping test
11672 // (this is an inline copy of IsClippedEx() so we can reuse the is_rect_visible value, otherwise we'd do 'if (IsClippedEx(bb, id)) return false')
11673 // g.NavActivateId is not necessarily == g.NavId, in the case of remote activation (e.g. shortcuts)
11674 const bool is_rect_visible = bb.Overlaps(window->ClipRect);
11675 if (!is_rect_visible)
11676 if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId && id != g.NavActivateId))
11677 if (!g.ItemUnclipByLog)
11678 return false;
11679
11680 // [DEBUG]
11681#ifndef IMGUI_DISABLE_DEBUG_TOOLS
11682 if (id != 0)
11683 {
11684 if (id == g.DebugLocateId)
11686
11687 // [DEBUG] People keep stumbling on this problem and using "" as identifier in the root of a window instead of "##something".
11688 // Empty identifier are valid and useful in a small amount of cases, but 99.9% of the time you want to use "##something".
11689 // READ THE FAQ: https://dearimgui.com/faq
11690 IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!");
11691
11692 // [DEBUG] Highlight all conflicts WITHOUT needing to hover. THIS WILL SLOW DOWN DEAR IMGUI. DON'T KEEP ACTIVATED.
11693 // This will only work for items submitted with ItemAdd(). Some very rare/odd/unrecommended code patterns are calling ButtonBehavior() without ItemAdd().
11694#ifdef IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
11696 {
11697 int* p_alive = g.DebugDrawIdConflictsAliveCount.GetIntRef(id, -1); // Could halve lookups if we knew ImGuiStorage can store 64-bit, or by storing FrameCount as 30-bits + highlight as 2-bits. But the point is that we should not pretend that this is fast.
11698 int* p_highlight = g.DebugDrawIdConflictsHighlightSet.GetIntRef(id, -1);
11699 if (*p_alive == g.FrameCount)
11700 *p_highlight = g.FrameCount;
11701 *p_alive = g.FrameCount;
11702 if (*p_highlight >= g.FrameCount - 1)
11703 window->DrawList->AddRect(bb.Min - ImVec2(1, 1), bb.Max + ImVec2(1, 1), IM_COL32(255, 0, 0, 255), 0.0f, ImDrawFlags_None, 2.0f);
11704 }
11705#endif
11706 }
11707 //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
11708 //if ((g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav) == 0)
11709 // window->DrawList->AddRect(g.LastItemData.NavRect.Min, g.LastItemData.NavRect.Max, IM_COL32(255,255,0,255)); // [DEBUG]
11710#endif
11711
11712 if (id != 0 && g.DeactivatedItemData.ID == id)
11714
11715 // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
11716 if (is_rect_visible)
11718 if (IsMouseHoveringRect(bb.Min, bb.Max))
11720 return true;
11721}
11723
11724//-----------------------------------------------------------------------------
11725// [SECTION] LAYOUT
11726//-----------------------------------------------------------------------------
11727// - ItemSize()
11728// - SameLine()
11729// - GetCursorScreenPos()
11730// - SetCursorScreenPos()
11731// - GetCursorPos(), GetCursorPosX(), GetCursorPosY()
11732// - SetCursorPos(), SetCursorPosX(), SetCursorPosY()
11733// - GetCursorStartPos()
11734// - Indent()
11735// - Unindent()
11736// - SetNextItemWidth()
11737// - PushItemWidth()
11738// - PushMultiItemsWidths()
11739// - PopItemWidth()
11740// - CalcItemWidth()
11741// - CalcItemSize()
11742// - GetTextLineHeight()
11743// - GetTextLineHeightWithSpacing()
11744// - GetFrameHeight()
11745// - GetFrameHeightWithSpacing()
11746// - GetContentRegionMax()
11747// - GetContentRegionAvail(),
11748// - BeginGroup()
11749// - EndGroup()
11750// Also see in imgui_widgets: tab bars, and in imgui_tables: tables, columns.
11751//-----------------------------------------------------------------------------
11752
11753// Advance cursor given item size for layout.
11754// Register minimum needed size so it can extend the bounding box used for auto-fit calculation.
11755// See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different.
11756// THIS IS IN THE PERFORMANCE CRITICAL PATH.
11758void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
11759{
11760 ImGuiContext& g = *GImGui;
11761 ImGuiWindow* window = g.CurrentWindow;
11762 if (window->SkipItems)
11763 return;
11764
11765 // We increase the height in this function to accommodate for baseline offset.
11766 // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
11767 // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
11768 const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f;
11769
11770 const float line_y1 = window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y;
11771 const float line_height = ImMax(window->DC.CurrLineSize.y, /*ImMax(*/window->DC.CursorPos.y - line_y1/*, 0.0f)*/ + size.y + offset_to_match_baseline_y);
11772
11773 // Always align ourselves on pixel boundaries
11774 //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
11775 window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
11776 window->DC.CursorPosPrevLine.y = line_y1;
11777 window->DC.CursorPos.x = IM_TRUNC(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); // Next line
11778 window->DC.CursorPos.y = IM_TRUNC(line_y1 + line_height + g.Style.ItemSpacing.y); // Next line
11779 window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
11780 window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
11781 //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
11782
11783 window->DC.PrevLineSize.y = line_height;
11784 window->DC.CurrLineSize.y = 0.0f;
11785 window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);
11786 window->DC.CurrLineTextBaseOffset = 0.0f;
11787 window->DC.IsSameLine = window->DC.IsSetPos = false;
11788
11789 // Horizontal layout mode
11791 SameLine();
11792}
11794
11795// Gets back to previous line and continue with horizontal layout
11796// offset_from_start_x == 0 : follow right after previous item
11797// offset_from_start_x != 0 : align to specified x position (relative to window/group left)
11798// spacing_w < 0 : use default spacing if offset_from_start_x == 0, no spacing if offset_from_start_x != 0
11799// spacing_w >= 0 : enforce spacing amount
11800void ImGui::SameLine(float offset_from_start_x, float spacing_w)
11801{
11802 ImGuiContext& g = *GImGui;
11803 ImGuiWindow* window = g.CurrentWindow;
11804 if (window->SkipItems)
11805 return;
11806
11807 if (offset_from_start_x != 0.0f)
11808 {
11809 if (spacing_w < 0.0f)
11810 spacing_w = 0.0f;
11811 window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x;
11812 window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
11813 }
11814 else
11815 {
11816 if (spacing_w < 0.0f)
11817 spacing_w = g.Style.ItemSpacing.x;
11818 window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
11819 window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
11820 }
11821 window->DC.CurrLineSize = window->DC.PrevLineSize;
11823 window->DC.IsSameLine = true;
11824}
11825
11827{
11829 return window->DC.CursorPos;
11830}
11831
11833{
11834 ImGuiWindow* window = GetCurrentWindow();
11835 window->DC.CursorPos = pos;
11836 //window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
11837 window->DC.IsSetPos = true;
11838}
11839
11840// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
11841// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.
11843{
11845 return window->DC.CursorPos - window->Pos + window->Scroll;
11846}
11847
11849{
11851 return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
11852}
11853
11855{
11857 return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
11858}
11859
11860void ImGui::SetCursorPos(const ImVec2& local_pos)
11861{
11862 ImGuiWindow* window = GetCurrentWindow();
11863 window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
11864 //window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
11865 window->DC.IsSetPos = true;
11866}
11867
11869{
11870 ImGuiWindow* window = GetCurrentWindow();
11871 window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
11872 //window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
11873 window->DC.IsSetPos = true;
11874}
11875
11877{
11878 ImGuiWindow* window = GetCurrentWindow();
11879 window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
11880 //window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
11881 window->DC.IsSetPos = true;
11882}
11883
11885{
11887 return window->DC.CursorStartPos - window->Pos;
11888}
11889
11890void ImGui::Indent(float indent_w)
11891{
11892 ImGuiContext& g = *GImGui;
11893 ImGuiWindow* window = GetCurrentWindow();
11894 window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
11895 window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
11896}
11897
11898void ImGui::Unindent(float indent_w)
11899{
11900 ImGuiContext& g = *GImGui;
11901 ImGuiWindow* window = GetCurrentWindow();
11902 window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
11903 window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
11904}
11905
11906// Affect large frame+labels widgets only.
11907void ImGui::SetNextItemWidth(float item_width)
11908{
11909 ImGuiContext& g = *GImGui;
11911 g.NextItemData.Width = item_width;
11912}
11913
11914// FIXME: Remove the == 0.0f behavior?
11915void ImGui::PushItemWidth(float item_width)
11916{
11917 ImGuiContext& g = *GImGui;
11918 ImGuiWindow* window = g.CurrentWindow;
11919 window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width
11920 window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
11921 g.NextItemData.HasFlags &= ~ImGuiNextItemDataFlags_HasWidth;
11922}
11923
11924void ImGui::PushMultiItemsWidths(int components, float w_full)
11925{
11926 ImGuiContext& g = *GImGui;
11927 ImGuiWindow* window = g.CurrentWindow;
11928 IM_ASSERT(components > 0);
11929 const ImGuiStyle& style = g.Style;
11930 window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width
11931 float w_items = w_full - style.ItemInnerSpacing.x * (components - 1);
11932 float prev_split = w_items;
11933 for (int i = components - 1; i > 0; i--)
11934 {
11935 float next_split = IM_TRUNC(w_items * i / components);
11936 window->DC.ItemWidthStack.push_back(ImMax(prev_split - next_split, 1.0f));
11937 prev_split = next_split;
11938 }
11939 window->DC.ItemWidth = ImMax(prev_split, 1.0f);
11940 g.NextItemData.HasFlags &= ~ImGuiNextItemDataFlags_HasWidth;
11941}
11942
11944{
11945 ImGuiContext& g = *GImGui;
11946 ImGuiWindow* window = g.CurrentWindow;
11947 if (window->DC.ItemWidthStack.Size <= 0)
11948 {
11949 IM_ASSERT_USER_ERROR(0, "Calling PopItemWidth() too many times!");
11950 return;
11951 }
11952 window->DC.ItemWidth = window->DC.ItemWidthStack.back();
11953 window->DC.ItemWidthStack.pop_back();
11954}
11955
11956// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
11957// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
11959{
11960 ImGuiContext& g = *GImGui;
11961 ImGuiWindow* window = g.CurrentWindow;
11962 float w;
11964 w = g.NextItemData.Width;
11965 else
11966 w = window->DC.ItemWidth;
11967 if (w < 0.0f)
11968 {
11969 float region_avail_x = GetContentRegionAvail().x;
11970 w = ImMax(1.0f, region_avail_x + w);
11971 }
11972 w = IM_TRUNC(w);
11973 return w;
11974}
11975
11976// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
11977// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
11978// Note that only CalcItemWidth() is publicly exposed.
11979// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
11980ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
11981{
11982 ImVec2 avail;
11983 if (size.x < 0.0f || size.y < 0.0f)
11984 avail = GetContentRegionAvail();
11985
11986 if (size.x == 0.0f)
11987 size.x = default_w;
11988 else if (size.x < 0.0f)
11989 size.x = ImMax(4.0f, avail.x + size.x); // <-- size.x is negative here so we are subtracting
11990
11991 if (size.y == 0.0f)
11992 size.y = default_h;
11993 else if (size.y < 0.0f)
11994 size.y = ImMax(4.0f, avail.y + size.y); // <-- size.y is negative here so we are subtracting
11995
11996 return size;
11997}
11998
12000{
12001 ImGuiContext& g = *GImGui;
12002 return g.FontSize;
12003}
12004
12006{
12007 ImGuiContext& g = *GImGui;
12008 return g.FontSize + g.Style.ItemSpacing.y;
12009}
12010
12012{
12013 ImGuiContext& g = *GImGui;
12014 return g.FontSize + g.Style.FramePadding.y * 2.0f;
12015}
12016
12018{
12019 ImGuiContext& g = *GImGui;
12020 return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
12021}
12022
12024{
12025 ImGuiContext& g = *GImGui;
12026 ImGuiWindow* window = g.CurrentWindow;
12027 ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max;
12028 return mx - window->DC.CursorPos;
12029}
12030
12031#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
12032
12033// You should never need those functions. Always use GetCursorScreenPos() and GetContentRegionAvail()!
12034// They are bizarre local-coordinates which don't play well with scrolling.
12036{
12038}
12039
12041{
12042 ImGuiWindow* window = GImGui->CurrentWindow;
12043 return window->ContentRegionRect.Min - window->Pos;
12044}
12045
12047{
12048 ImGuiWindow* window = GImGui->CurrentWindow;
12049 return window->ContentRegionRect.Max - window->Pos;
12050}
12051#endif
12052
12053// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
12054// Groups are currently a mishmash of functionalities which should perhaps be clarified and separated.
12055// FIXME-OPT: Could we safely early out on ->SkipItems?
12057{
12058 ImGuiContext& g = *GImGui;
12059 ImGuiWindow* window = g.CurrentWindow;
12060
12062 ImGuiGroupData& group_data = g.GroupStack.back();
12063 group_data.WindowID = window->ID;
12064 group_data.BackupCursorPos = window->DC.CursorPos;
12065 group_data.BackupCursorPosPrevLine = window->DC.CursorPosPrevLine;
12066 group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
12067 group_data.BackupIndent = window->DC.Indent;
12068 group_data.BackupGroupOffset = window->DC.GroupOffset;
12069 group_data.BackupCurrLineSize = window->DC.CurrLineSize;
12072 group_data.BackupHoveredIdIsAlive = g.HoveredId != 0;
12073 group_data.BackupIsSameLine = window->DC.IsSameLine;
12075 group_data.EmitItem = true;
12076
12077 window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
12078 window->DC.Indent = window->DC.GroupOffset;
12079 window->DC.CursorMaxPos = window->DC.CursorPos;
12080 window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
12081 if (g.LogEnabled)
12082 g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
12083}
12084
12086{
12087 ImGuiContext& g = *GImGui;
12088 ImGuiWindow* window = g.CurrentWindow;
12089 IM_ASSERT(g.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls
12090
12091 ImGuiGroupData& group_data = g.GroupStack.back();
12092 IM_ASSERT(group_data.WindowID == window->ID); // EndGroup() in wrong window?
12093
12094 if (window->DC.IsSetPos)
12096
12097 // Include LastItemData.Rect.Max as a workaround for e.g. EndTable() undershooting with CursorMaxPos report. (#7543)
12098 ImRect group_bb(group_data.BackupCursorPos, ImMax(ImMax(window->DC.CursorMaxPos, g.LastItemData.Rect.Max), group_data.BackupCursorPos));
12099 window->DC.CursorPos = group_data.BackupCursorPos;
12100 window->DC.CursorPosPrevLine = group_data.BackupCursorPosPrevLine;
12101 window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, group_bb.Max);
12102 window->DC.Indent = group_data.BackupIndent;
12103 window->DC.GroupOffset = group_data.BackupGroupOffset;
12104 window->DC.CurrLineSize = group_data.BackupCurrLineSize;
12106 window->DC.IsSameLine = group_data.BackupIsSameLine;
12107 if (g.LogEnabled)
12108 g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
12109
12110 if (!group_data.EmitItem)
12111 {
12112 g.GroupStack.pop_back();
12113 return;
12114 }
12115
12116 window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
12117 ItemSize(group_bb.GetSize());
12118 ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop);
12119
12120 // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
12121 // It would be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
12122 // Also if you grep for LastItemId you'll notice it is only used in that context.
12123 // (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
12124 const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
12125 const bool group_contains_deactivated_id = (group_data.BackupDeactivatedIdIsAlive == false) && (g.DeactivatedItemData.IsAlive == true);
12126 if (group_contains_curr_active_id)
12127 g.LastItemData.ID = g.ActiveId;
12128 else if (group_contains_deactivated_id)
12130 g.LastItemData.Rect = group_bb;
12131
12132 // Forward Hovered flag
12133 const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0;
12134 if (group_contains_curr_hovered_id)
12136
12137 // Forward Edited flag
12138 if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
12140
12141 // Forward Deactivated flag
12143 if (group_contains_deactivated_id)
12145
12146 g.GroupStack.pop_back();
12147 if (g.DebugShowGroupRects)
12148 window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
12149}
12150
12151
12152//-----------------------------------------------------------------------------
12153// [SECTION] SCROLLING
12154//-----------------------------------------------------------------------------
12155
12156// Helper to snap on edges when aiming at an item very close to the edge,
12157// So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling.
12158// When we refactor the scrolling API this may be configurable with a flag?
12159// Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default.
12160static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio)
12161{
12162 if (target <= snap_min + snap_threshold)
12163 return ImLerp(snap_min, target, center_ratio);
12164 if (target >= snap_max - snap_threshold)
12165 return ImLerp(target, snap_max, center_ratio);
12166 return target;
12167}
12168
12170{
12171 ImVec2 scroll = window->Scroll;
12172 ImVec2 decoration_size(window->DecoOuterSizeX1 + window->DecoInnerSizeX1 + window->DecoOuterSizeX2, window->DecoOuterSizeY1 + window->DecoInnerSizeY1 + window->DecoOuterSizeY2);
12173 for (int axis = 0; axis < 2; axis++)
12174 {
12175 if (window->ScrollTarget[axis] < FLT_MAX)
12176 {
12177 float center_ratio = window->ScrollTargetCenterRatio[axis];
12178 float scroll_target = window->ScrollTarget[axis];
12179 if (window->ScrollTargetEdgeSnapDist[axis] > 0.0f)
12180 {
12181 float snap_min = 0.0f;
12182 float snap_max = window->ScrollMax[axis] + window->SizeFull[axis] - decoration_size[axis];
12183 scroll_target = CalcScrollEdgeSnap(scroll_target, snap_min, snap_max, window->ScrollTargetEdgeSnapDist[axis], center_ratio);
12184 }
12185 scroll[axis] = scroll_target - center_ratio * (window->SizeFull[axis] - decoration_size[axis]);
12186 }
12187 scroll[axis] = ImRound64(ImMax(scroll[axis], 0.0f));
12188 if (!window->Collapsed && !window->SkipItems)
12189 scroll[axis] = ImMin(scroll[axis], window->ScrollMax[axis]);
12190 }
12191 return scroll;
12192}
12193
12195{
12196 ImGuiContext& g = *GImGui;
12197 ImGuiWindow* window = g.CurrentWindow;
12198 ScrollToRectEx(window, g.LastItemData.NavRect, flags);
12199}
12200
12201void ImGui::ScrollToRect(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags)
12202{
12203 ScrollToRectEx(window, item_rect, flags);
12204}
12205
12206// Scroll to keep newly navigated item fully into view
12208{
12209 ImGuiContext& g = *GImGui;
12210 ImRect scroll_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
12211 scroll_rect.Min.x = ImMin(scroll_rect.Min.x + window->DecoInnerSizeX1, scroll_rect.Max.x);
12212 scroll_rect.Min.y = ImMin(scroll_rect.Min.y + window->DecoInnerSizeY1, scroll_rect.Max.y);
12213 //GetForegroundDrawList(window)->AddRect(item_rect.Min, item_rect.Max, IM_COL32(255,0,0,255), 0.0f, 0, 5.0f); // [DEBUG]
12214 //GetForegroundDrawList(window)->AddRect(scroll_rect.Min, scroll_rect.Max, IM_COL32_WHITE); // [DEBUG]
12215
12216 // Check that only one behavior is selected per axis
12219
12220 // Defaults
12221 ImGuiScrollFlags in_flags = flags;
12222 if ((flags & ImGuiScrollFlags_MaskX_) == 0 && window->ScrollbarX)
12224 if ((flags & ImGuiScrollFlags_MaskY_) == 0)
12226
12227 const bool fully_visible_x = item_rect.Min.x >= scroll_rect.Min.x && item_rect.Max.x <= scroll_rect.Max.x;
12228 const bool fully_visible_y = item_rect.Min.y >= scroll_rect.Min.y && item_rect.Max.y <= scroll_rect.Max.y;
12229 const bool can_be_fully_visible_x = (item_rect.GetWidth() + g.Style.ItemSpacing.x * 2.0f) <= scroll_rect.GetWidth() || (window->AutoFitFramesX > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0;
12230 const bool can_be_fully_visible_y = (item_rect.GetHeight() + g.Style.ItemSpacing.y * 2.0f) <= scroll_rect.GetHeight() || (window->AutoFitFramesY > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0;
12231
12232 if ((flags & ImGuiScrollFlags_KeepVisibleEdgeX) && !fully_visible_x)
12233 {
12234 if (item_rect.Min.x < scroll_rect.Min.x || !can_be_fully_visible_x)
12235 SetScrollFromPosX(window, item_rect.Min.x - g.Style.ItemSpacing.x - window->Pos.x, 0.0f);
12236 else if (item_rect.Max.x >= scroll_rect.Max.x)
12237 SetScrollFromPosX(window, item_rect.Max.x + g.Style.ItemSpacing.x - window->Pos.x, 1.0f);
12238 }
12239 else if (((flags & ImGuiScrollFlags_KeepVisibleCenterX) && !fully_visible_x) || (flags & ImGuiScrollFlags_AlwaysCenterX))
12240 {
12241 if (can_be_fully_visible_x)
12242 SetScrollFromPosX(window, ImTrunc((item_rect.Min.x + item_rect.Max.x) * 0.5f) - window->Pos.x, 0.5f);
12243 else
12244 SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x, 0.0f);
12245 }
12246
12247 if ((flags & ImGuiScrollFlags_KeepVisibleEdgeY) && !fully_visible_y)
12248 {
12249 if (item_rect.Min.y < scroll_rect.Min.y || !can_be_fully_visible_y)
12250 SetScrollFromPosY(window, item_rect.Min.y - g.Style.ItemSpacing.y - window->Pos.y, 0.0f);
12251 else if (item_rect.Max.y >= scroll_rect.Max.y)
12252 SetScrollFromPosY(window, item_rect.Max.y + g.Style.ItemSpacing.y - window->Pos.y, 1.0f);
12253 }
12254 else if (((flags & ImGuiScrollFlags_KeepVisibleCenterY) && !fully_visible_y) || (flags & ImGuiScrollFlags_AlwaysCenterY))
12255 {
12256 if (can_be_fully_visible_y)
12257 SetScrollFromPosY(window, ImTrunc((item_rect.Min.y + item_rect.Max.y) * 0.5f) - window->Pos.y, 0.5f);
12258 else
12259 SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y, 0.0f);
12260 }
12261
12262 ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
12263 ImVec2 delta_scroll = next_scroll - window->Scroll;
12264
12265 // Also scroll parent window to keep us into view if necessary
12267 {
12268 // FIXME-SCROLL: May be an option?
12270 in_flags = (in_flags & ~ImGuiScrollFlags_MaskX_) | ImGuiScrollFlags_KeepVisibleEdgeX;
12273 delta_scroll += ScrollToRectEx(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll), in_flags);
12274 }
12275
12276 return delta_scroll;
12277}
12278
12280{
12281 ImGuiWindow* window = GImGui->CurrentWindow;
12282 return window->Scroll.x;
12283}
12284
12286{
12287 ImGuiWindow* window = GImGui->CurrentWindow;
12288 return window->Scroll.y;
12289}
12290
12292{
12293 ImGuiWindow* window = GImGui->CurrentWindow;
12294 return window->ScrollMax.x;
12295}
12296
12298{
12299 ImGuiWindow* window = GImGui->CurrentWindow;
12300 return window->ScrollMax.y;
12301}
12302
12303void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x)
12304{
12305 window->ScrollTarget.x = scroll_x;
12306 window->ScrollTargetCenterRatio.x = 0.0f;
12307 window->ScrollTargetEdgeSnapDist.x = 0.0f;
12308}
12309
12310void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y)
12311{
12312 window->ScrollTarget.y = scroll_y;
12313 window->ScrollTargetCenterRatio.y = 0.0f;
12314 window->ScrollTargetEdgeSnapDist.y = 0.0f;
12315}
12316
12317void ImGui::SetScrollX(float scroll_x)
12318{
12319 ImGuiContext& g = *GImGui;
12320 SetScrollX(g.CurrentWindow, scroll_x);
12321}
12322
12323void ImGui::SetScrollY(float scroll_y)
12324{
12325 ImGuiContext& g = *GImGui;
12326 SetScrollY(g.CurrentWindow, scroll_y);
12327}
12328
12329// Note that a local position will vary depending on initial scroll value,
12330// This is a little bit confusing so bear with us:
12331// - local_pos = (absolution_pos - window->Pos)
12332// - So local_x/local_y are 0.0f for a position at the upper-left corner of a window,
12333// and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area.
12334// - They mostly exist because of legacy API.
12335// Following the rules above, when trying to work with scrolling code, consider that:
12336// - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect!
12337// - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense
12338// We store a target position so centering and clamping can occur on the next frame when we are guaranteed to have a known window size
12339void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio)
12340{
12341 IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
12342 window->ScrollTarget.x = IM_TRUNC(local_x - window->DecoOuterSizeX1 - window->DecoInnerSizeX1 + window->Scroll.x); // Convert local position to scroll offset
12343 window->ScrollTargetCenterRatio.x = center_x_ratio;
12344 window->ScrollTargetEdgeSnapDist.x = 0.0f;
12345}
12346
12347void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio)
12348{
12349 IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
12350 window->ScrollTarget.y = IM_TRUNC(local_y - window->DecoOuterSizeY1 - window->DecoInnerSizeY1 + window->Scroll.y); // Convert local position to scroll offset
12351 window->ScrollTargetCenterRatio.y = center_y_ratio;
12352 window->ScrollTargetEdgeSnapDist.y = 0.0f;
12353}
12354
12355void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
12356{
12357 ImGuiContext& g = *GImGui;
12358 SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio);
12359}
12360
12361void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
12362{
12363 ImGuiContext& g = *GImGui;
12364 SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio);
12365}
12366
12367// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item.
12368void ImGui::SetScrollHereX(float center_x_ratio)
12369{
12370 ImGuiContext& g = *GImGui;
12371 ImGuiWindow* window = g.CurrentWindow;
12372 float spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x);
12373 float target_pos_x = ImLerp(g.LastItemData.Rect.Min.x - spacing_x, g.LastItemData.Rect.Max.x + spacing_x, center_x_ratio);
12374 SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos
12375
12376 // Tweak: snap on edges when aiming at an item very close to the edge
12377 window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x);
12378}
12379
12380// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
12381void ImGui::SetScrollHereY(float center_y_ratio)
12382{
12383 ImGuiContext& g = *GImGui;
12384 ImGuiWindow* window = g.CurrentWindow;
12385 float spacing_y = ImMax(window->WindowPadding.y, g.Style.ItemSpacing.y);
12386 float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio);
12387 SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos
12388
12389 // Tweak: snap on edges when aiming at an item very close to the edge
12390 window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y);
12391}
12392
12393//-----------------------------------------------------------------------------
12394// [SECTION] TOOLTIPS
12395//-----------------------------------------------------------------------------
12396
12398{
12400}
12401
12403{
12405 return false;
12407}
12408
12409bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags)
12410{
12411 ImGuiContext& g = *GImGui;
12412
12413 const bool is_dragdrop_tooltip = g.DragDropWithinSource || g.DragDropWithinTarget;
12414 if (is_dragdrop_tooltip)
12415 {
12416 // Drag and Drop tooltips are positioning differently than other tooltips:
12417 // - offset visibility to increase visibility around mouse.
12418 // - never clamp within outer viewport boundary.
12419 // We call SetNextWindowPos() to enforce position and disable clamping.
12420 // See FindBestWindowPosForPopup() for positioning logic of other tooltips (not drag and drop ones).
12421 //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding;
12422 const bool is_touchscreen = (g.IO.MouseSource == ImGuiMouseSource_TouchScreen);
12424 {
12426 ImVec2 tooltip_pivot = is_touchscreen ? TOOLTIP_DEFAULT_PIVOT_TOUCH : ImVec2(0.0f, 0.0f);
12427 SetNextWindowPos(tooltip_pos, ImGuiCond_None, tooltip_pivot);
12428 }
12429
12431 //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :(
12432 tooltip_flags |= ImGuiTooltipFlags_OverridePrevious;
12433 }
12434
12435 const char* window_name_template = is_dragdrop_tooltip ? "##Tooltip_DragDrop_%02d" : "##Tooltip_%02d";
12436 char window_name[32];
12437 ImFormatString(window_name, IM_ARRAYSIZE(window_name), window_name_template, g.TooltipOverrideCount);
12439 {
12440 // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
12441 //IMGUI_DEBUG_LOG("[tooltip] '%s' already active, using +1 for this frame\n", window_name);
12443 ImFormatString(window_name, IM_ARRAYSIZE(window_name), window_name_template, ++g.TooltipOverrideCount);
12444 }
12445
12447 Begin(window_name, NULL, flags | extra_window_flags);
12448 // 2023-03-09: Added bool return value to the API, but currently always returning true.
12449 // If this ever returns false we need to update BeginDragDropSource() accordingly.
12450 //if (!ret)
12451 // End();
12452 //return ret;
12453 return true;
12454}
12455
12457{
12458 IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls
12459 End();
12460}
12461
12462void ImGui::SetTooltip(const char* fmt, ...)
12463{
12464 va_list args;
12465 va_start(args, fmt);
12466 SetTooltipV(fmt, args);
12467 va_end(args);
12468}
12469
12470void ImGui::SetTooltipV(const char* fmt, va_list args)
12471{
12473 return;
12474 TextV(fmt, args);
12475 EndTooltip();
12476}
12477
12478// Shortcut to use 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav'.
12479// Defaults to == ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort when using the mouse.
12480void ImGui::SetItemTooltip(const char* fmt, ...)
12481{
12482 va_list args;
12483 va_start(args, fmt);
12485 SetTooltipV(fmt, args);
12486 va_end(args);
12487}
12488
12489void ImGui::SetItemTooltipV(const char* fmt, va_list args)
12490{
12492 SetTooltipV(fmt, args);
12493}
12494
12495
12496//-----------------------------------------------------------------------------
12497// [SECTION] POPUPS
12498//-----------------------------------------------------------------------------
12499
12500// Supported flags: ImGuiPopupFlags_AnyPopupId, ImGuiPopupFlags_AnyPopupLevel
12502{
12503 ImGuiContext& g = *GImGui;
12504 if (popup_flags & ImGuiPopupFlags_AnyPopupId)
12505 {
12506 // Return true if any popup is open at the current BeginPopup() level of the popup stack
12507 // This may be used to e.g. test for another popups already opened to handle popups priorities at the same level.
12508 IM_ASSERT(id == 0);
12509 if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
12510 return g.OpenPopupStack.Size > 0;
12511 else
12513 }
12514 else
12515 {
12516 if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
12517 {
12518 // Return true if the popup is open anywhere in the popup stack
12519 for (ImGuiPopupData& popup_data : g.OpenPopupStack)
12520 if (popup_data.PopupId == id)
12521 return true;
12522 return false;
12523 }
12524 else
12525 {
12526 // Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query)
12527 return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
12528 }
12529 }
12530}
12531
12532bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags)
12533{
12534 ImGuiContext& g = *GImGui;
12535 ImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id);
12536 if ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0)
12537 IM_ASSERT(0 && "Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel."); // But non-string version is legal and used internally
12538 return IsPopupOpen(id, popup_flags);
12539}
12540
12541// Also see FindBlockingModal(NULL)
12543{
12544 ImGuiContext& g = *GImGui;
12545 for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)
12546 if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
12547 if (popup->Flags & ImGuiWindowFlags_Modal)
12548 return popup;
12549 return NULL;
12550}
12551
12552// See Demo->Stacked Modal to confirm what this is for.
12554{
12555 ImGuiContext& g = *GImGui;
12556 for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)
12557 if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
12558 if ((popup->Flags & ImGuiWindowFlags_Modal) && IsWindowActiveAndVisible(popup))
12559 return popup;
12560 return NULL;
12561}
12562
12563
12564// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing)
12565// should be positioned behind that modal window, unless the window was created inside the modal begin-stack.
12566// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent.
12567// - WindowA // FindBlockingModal() returns Modal1
12568// - WindowB // .. returns Modal1
12569// - Modal1 // .. returns Modal2
12570// - WindowC // .. returns Modal2
12571// - WindowD // .. returns Modal2
12572// - Modal2 // .. returns Modal2
12573// - WindowE // .. returns NULL
12574// Notes:
12575// - FindBlockingModal(NULL) == NULL is generally equivalent to GetTopMostPopupModal() == NULL.
12576// Only difference is here we check for ->Active/WasActive but it may be unnecessary.
12578{
12579 ImGuiContext& g = *GImGui;
12580 if (g.OpenPopupStack.Size <= 0)
12581 return NULL;
12582
12583 // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal.
12584 for (ImGuiPopupData& popup_data : g.OpenPopupStack)
12585 {
12586 ImGuiWindow* popup_window = popup_data.Window;
12587 if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal))
12588 continue;
12589 if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows.
12590 continue;
12591 if (window == NULL) // FindBlockingModal(NULL) test for if FocusWindow(NULL) is naturally possible via a mouse click.
12592 return popup_window;
12593 if (IsWindowWithinBeginStackOf(window, popup_window)) // Window may be over modal
12594 continue;
12595 return popup_window; // Place window right below first block modal
12596 }
12597 return NULL;
12598}
12599
12600void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags)
12601{
12602 ImGuiContext& g = *GImGui;
12603 ImGuiID id = g.CurrentWindow->GetID(str_id);
12604 IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopup(\"%s\" -> 0x%08X)\n", str_id, id);
12605 OpenPopupEx(id, popup_flags);
12606}
12607
12609{
12610 OpenPopupEx(id, popup_flags);
12611}
12612
12613// Mark popup as open (toggle toward open state).
12614// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
12615// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
12616// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
12618{
12619 ImGuiContext& g = *GImGui;
12620 ImGuiWindow* parent_window = g.CurrentWindow;
12621 const int current_stack_size = g.BeginPopupStack.Size;
12622
12625 return;
12626
12627 ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
12628 popup_ref.PopupId = id;
12629 popup_ref.Window = NULL;
12630 popup_ref.RestoreNavWindow = g.NavWindow; // When popup closes focus may be restored to NavWindow (depend on window type).
12631 popup_ref.OpenFrameCount = g.FrameCount;
12632 popup_ref.OpenParentId = parent_window->IDStack.back();
12634 popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;
12635
12636 IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopupEx(0x%08X)\n", id);
12637 if (g.OpenPopupStack.Size < current_stack_size + 1)
12638 {
12639 g.OpenPopupStack.push_back(popup_ref);
12640 }
12641 else
12642 {
12643 // Gently handle the user mistakenly calling OpenPopup() every frames: it is likely a programming mistake!
12644 // However, if we were to run the regular code path, the ui would become completely unusable because the popup will always be
12645 // in hidden-while-calculating-size state _while_ claiming focus. Which is extremely confusing situation for the programmer.
12646 // Instead, for successive frames calls to OpenPopup(), we silently avoid reopening even if ImGuiPopupFlags_NoReopen is not specified.
12647 bool keep_existing = false;
12648 if (g.OpenPopupStack[current_stack_size].PopupId == id)
12649 if ((g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) || (popup_flags & ImGuiPopupFlags_NoReopen))
12650 keep_existing = true;
12651 if (keep_existing)
12652 {
12653 // No reopen
12654 g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
12655 }
12656 else
12657 {
12658 // Reopen: close child popups if any, then flag popup for open/reopen (set position, focus, init navigation)
12659 ClosePopupToLevel(current_stack_size, true);
12660 g.OpenPopupStack.push_back(popup_ref);
12661 }
12662
12663 // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
12664 // This is equivalent to what ClosePopupToLevel() does.
12665 //if (g.OpenPopupStack[current_stack_size].PopupId == id)
12666 // FocusWindow(parent_window);
12667 }
12668}
12669
12670// When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
12671// This function closes any popups that are over 'ref_window'.
12672void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup)
12673{
12674 ImGuiContext& g = *GImGui;
12675 if (g.OpenPopupStack.Size == 0)
12676 return;
12677
12678 // Don't close our own child popup windows.
12679 //IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupsOverWindow(\"%s\") restore_under=%d\n", ref_window ? ref_window->Name : "<NULL>", restore_focus_to_window_under_popup);
12680 int popup_count_to_keep = 0;
12681 if (ref_window)
12682 {
12683 // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow)
12684 for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)
12685 {
12686 ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep];
12687 if (!popup.Window)
12688 continue;
12690
12691 // Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow)
12692 // - Clicking/Focusing Window2 won't close Popup1:
12693 // Window -> Popup1 -> Window2(Ref)
12694 // - Clicking/focusing Popup1 will close Popup2 and Popup3:
12695 // Window -> Popup1(Ref) -> Popup2 -> Popup3
12696 // - Each popups may contain child windows, which is why we compare ->RootWindowDockTree!
12697 // Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child
12698 // We step through every popup from bottom to top to validate their position relative to reference window.
12699 bool ref_window_is_descendent_of_popup = false;
12700 for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++)
12701 if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window)
12702 //if (popup_window->RootWindowDockTree == ref_window->RootWindowDockTree) // FIXME-MERGE
12703 if (IsWindowWithinBeginStackOf(ref_window, popup_window))
12704 {
12705 ref_window_is_descendent_of_popup = true;
12706 break;
12707 }
12708 if (!ref_window_is_descendent_of_popup)
12709 break;
12710 }
12711 }
12712 if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below
12713 {
12714 IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupsOverWindow(\"%s\")\n", ref_window ? ref_window->Name : "<NULL>");
12715 ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup);
12716 }
12717}
12718
12720{
12721 ImGuiContext& g = *GImGui;
12722
12723 int popup_count_to_keep;
12724 for (popup_count_to_keep = g.OpenPopupStack.Size; popup_count_to_keep > 0; popup_count_to_keep--)
12725 {
12726 ImGuiWindow* window = g.OpenPopupStack[popup_count_to_keep - 1].Window;
12727 if (!window || (window->Flags & ImGuiWindowFlags_Modal))
12728 break;
12729 }
12730 if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below
12731 ClosePopupToLevel(popup_count_to_keep, true);
12732}
12733
12734void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)
12735{
12736 ImGuiContext& g = *GImGui;
12737 IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupToLevel(%d), restore_under=%d\n", remaining, restore_focus_to_window_under_popup);
12738 IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);
12740 for (int n = remaining; n < g.OpenPopupStack.Size; n++)
12741 IMGUI_DEBUG_LOG_POPUP("[popup] - Closing PopupID 0x%08X Window \"%s\"\n", g.OpenPopupStack[n].PopupId, g.OpenPopupStack[n].Window ? g.OpenPopupStack[n].Window->Name : NULL);
12742
12743 // Trim open popup stack
12744 ImGuiPopupData prev_popup = g.OpenPopupStack[remaining];
12745 g.OpenPopupStack.resize(remaining);
12746
12747 // Restore focus (unless popup window was not yet submitted, and didn't have a chance to take focus anyhow. See #7325 for an edge case)
12748 if (restore_focus_to_window_under_popup && prev_popup.Window)
12749 {
12750 ImGuiWindow* popup_window = prev_popup.Window;
12751 ImGuiWindow* focus_window = (popup_window->Flags & ImGuiWindowFlags_ChildMenu) ? popup_window->ParentWindow : prev_popup.RestoreNavWindow;
12752 if (focus_window && !focus_window->WasActive)
12753 FocusTopMostWindowUnderOne(popup_window, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild); // Fallback
12754 else
12756 }
12757}
12758
12759// Close the popup we have begin-ed into.
12761{
12762 ImGuiContext& g = *GImGui;
12763 int popup_idx = g.BeginPopupStack.Size - 1;
12764 if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
12765 return;
12766
12767 // Closing a menu closes its top-most parent popup (unless a modal)
12768 while (popup_idx > 0)
12769 {
12770 ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window;
12771 ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window;
12772 bool close_parent = false;
12773 if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu))
12774 if (parent_popup_window && !(parent_popup_window->Flags & ImGuiWindowFlags_MenuBar))
12775 close_parent = true;
12776 if (!close_parent)
12777 break;
12778 popup_idx--;
12779 }
12780 IMGUI_DEBUG_LOG_POPUP("[popup] CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx);
12781 ClosePopupToLevel(popup_idx, true);
12782
12783 // A common pattern is to close a popup when selecting a menu item/selectable that will open another window.
12784 // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window.
12785 // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic.
12786 if (ImGuiWindow* window = g.NavWindow)
12787 window->DC.NavHideHighlightOneFrame = true;
12788}
12789
12790// Attention! BeginPopup() adds default flags when calling BeginPopupEx()!
12792{
12793 ImGuiContext& g = *GImGui;
12795 {
12796 g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
12797 return false;
12798 }
12799
12800 char name[20];
12801 IM_ASSERT((extra_window_flags & ImGuiWindowFlags_ChildMenu) == 0); // Use BeginPopupMenuEx()
12802 ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // No recycling, so we can close/open during the same frame
12803
12804 bool is_open = Begin(name, NULL, extra_window_flags | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoDocking);
12805 if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
12806 EndPopup();
12807 //g.CurrentWindow->FocusRouteParentWindow = g.CurrentWindow->ParentWindowInBeginStack;
12808 return is_open;
12809}
12810
12811bool ImGui::BeginPopupMenuEx(ImGuiID id, const char* label, ImGuiWindowFlags extra_window_flags)
12812{
12813 ImGuiContext& g = *GImGui;
12815 {
12816 g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
12817 return false;
12818 }
12819
12820 char name[128];
12821 IM_ASSERT(extra_window_flags & ImGuiWindowFlags_ChildMenu);
12822 ImFormatString(name, IM_ARRAYSIZE(name), "%s###Menu_%02d", label, g.BeginMenuDepth); // Recycle windows based on depth
12823 bool is_open = Begin(name, NULL, extra_window_flags | ImGuiWindowFlags_Popup);
12824 if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
12825 EndPopup();
12826 //g.CurrentWindow->FocusRouteParentWindow = g.CurrentWindow->ParentWindowInBeginStack;
12827 return is_open;
12828}
12829
12830bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
12831{
12832 ImGuiContext& g = *GImGui;
12833 if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
12834 {
12835 g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
12836 return false;
12837 }
12839 ImGuiID id = g.CurrentWindow->GetID(str_id);
12840 return BeginPopupEx(id, flags);
12841}
12842
12843// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
12844// Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup).
12845// - *p_open set back to false in BeginPopupModal() when popup is not open.
12846// - if you set *p_open to false before calling BeginPopupModal(), it will close the popup.
12847bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
12848{
12849 ImGuiContext& g = *GImGui;
12850 ImGuiWindow* window = g.CurrentWindow;
12851 const ImGuiID id = window->GetID(name);
12853 {
12854 g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
12855 if (p_open && *p_open)
12856 *p_open = false;
12857 return false;
12858 }
12859
12860 // Center modal windows by default for increased visibility
12861 // (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves)
12862 // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
12864 {
12865 const ImGuiViewport* viewport = window->WasActive ? window->Viewport : GetMainViewport(); // FIXME-VIEWPORT: What may be our reference viewport?
12866 SetNextWindowPos(viewport->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
12867 }
12868
12870 const bool is_open = Begin(name, p_open, flags);
12871 if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
12872 {
12873 EndPopup();
12874 if (is_open)
12876 return false;
12877 }
12878 return is_open;
12879}
12880
12882{
12883 ImGuiContext& g = *GImGui;
12884 ImGuiWindow* window = g.CurrentWindow;
12885 if ((window->Flags & ImGuiWindowFlags_Popup) == 0 || g.BeginPopupStack.Size == 0)
12886 {
12887 IM_ASSERT_USER_ERROR(0, "Calling EndPopup() too many times or in wrong window!");
12888 return;
12889 }
12890
12891 // Make all menus and popups wrap around for now, may need to expose that policy (e.g. focus scope could include wrap/loop policy flags used by new move requests)
12892 if (g.NavWindow == window)
12894
12895 // Child-popups don't need to be laid out
12896 const ImGuiID backup_within_end_child_id = g.WithinEndChildID;
12897 if (window->Flags & ImGuiWindowFlags_ChildWindow)
12898 g.WithinEndChildID = window->ID;
12899 End();
12900 g.WithinEndChildID = backup_within_end_child_id;
12901}
12902
12903// Helper to open a popup if mouse button is released over the item
12904// - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup()
12905void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags)
12906{
12907 ImGuiContext& g = *GImGui;
12908 ImGuiWindow* window = g.CurrentWindow;
12909 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
12911 {
12912 ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
12913 IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
12914 OpenPopupEx(id, popup_flags);
12915 }
12916}
12917
12918// This is a helper to handle the simplest case of associating one named popup to one given widget.
12919// - To create a popup associated to the last item, you generally want to pass a NULL value to str_id.
12920// - To create a popup with a specific identifier, pass it in str_id.
12921// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call.
12922// - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id.
12923// - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
12924// This is essentially the same as:
12925// id = str_id ? GetID(str_id) : GetItemID();
12926// OpenPopupOnItemClick(str_id, ImGuiPopupFlags_MouseButtonRight);
12927// return BeginPopup(id);
12928// Which is essentially the same as:
12929// id = str_id ? GetID(str_id) : GetItemID();
12930// if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
12931// OpenPopup(id);
12932// return BeginPopup(id);
12933// The main difference being that this is tweaked to avoid computing the ID twice.
12934bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
12935{
12936 ImGuiContext& g = *GImGui;
12937 ImGuiWindow* window = g.CurrentWindow;
12938 if (window->SkipItems)
12939 return false;
12940 ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
12941 IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
12942 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
12944 OpenPopupEx(id, popup_flags);
12946}
12947
12948bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags)
12949{
12950 ImGuiContext& g = *GImGui;
12951 ImGuiWindow* window = g.CurrentWindow;
12952 if (!str_id)
12953 str_id = "window_context";
12954 ImGuiID id = window->GetID(str_id);
12955 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
12957 if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered())
12958 OpenPopupEx(id, popup_flags);
12960}
12961
12962bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags)
12963{
12964 ImGuiContext& g = *GImGui;
12965 ImGuiWindow* window = g.CurrentWindow;
12966 if (!str_id)
12967 str_id = "void_context";
12968 ImGuiID id = window->GetID(str_id);
12969 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
12971 if (GetTopMostPopupModal() == NULL)
12972 OpenPopupEx(id, popup_flags);
12974}
12975
12976// r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.)
12977// r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it.
12978// (r_outer is usually equivalent to the viewport rectangle minus padding, but when multi-viewports are enabled and monitor
12979// information are available, it may represent the entire platform monitor from the frame of reference of the current viewport.
12980// this allows us to have tooltips/popups displayed out of the parent viewport.)
12981ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy)
12982{
12983 ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);
12984 //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255));
12985 //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255));
12986
12987 // Combo Box policy (we want a connecting edge)
12989 {
12991 for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
12992 {
12993 const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
12994 if (n != -1 && dir == *last_dir) // Already tried this direction?
12995 continue;
12996 ImVec2 pos;
12997 if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default)
12998 if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right
12999 if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left
13000 if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left
13001 if (!r_outer.Contains(ImRect(pos, pos + size)))
13002 continue;
13003 *last_dir = dir;
13004 return pos;
13005 }
13006 }
13007
13008 // Tooltip and Default popup policy
13009 // (Always first try the direction we used on the last frame, if any)
13011 {
13013 for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
13014 {
13015 const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
13016 if (n != -1 && dir == *last_dir) // Already tried this direction?
13017 continue;
13018
13019 const float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x);
13020 const float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y);
13021
13022 // If there's not enough room on one axis, there's no point in positioning on a side on this axis (e.g. when not enough width, use a top/bottom position to maximize available width)
13023 if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right))
13024 continue;
13025 if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down))
13026 continue;
13027
13028 ImVec2 pos;
13029 pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
13030 pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y;
13031
13032 // Clamp top-left corner of popup
13033 pos.x = ImMax(pos.x, r_outer.Min.x);
13034 pos.y = ImMax(pos.y, r_outer.Min.y);
13035
13036 *last_dir = dir;
13037 return pos;
13038 }
13039 }
13040
13041 // Fallback when not enough room:
13042 *last_dir = ImGuiDir_None;
13043
13044 // For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
13046 return ref_pos + ImVec2(2, 2);
13047
13048 // Otherwise try to keep within display
13049 ImVec2 pos = ref_pos;
13050 pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
13051 pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
13052 return pos;
13053}
13054
13055// Note that this is used for popups, which can overlap the non work-area of individual viewports.
13057{
13058 ImGuiContext& g = *GImGui;
13059 ImRect r_screen;
13060 if (window->ViewportAllowPlatformMonitorExtend >= 0)
13061 {
13062 // Extent with be in the frame of reference of the given viewport (so Min is likely to be negative here)
13064 r_screen.Min = monitor.WorkPos;
13065 r_screen.Max = monitor.WorkPos + monitor.WorkSize;
13066 }
13067 else
13068 {
13069 // Use the full viewport area (not work area) for popups
13070 r_screen = window->Viewport->GetMainRect();
13071 }
13073 r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f));
13074 return r_screen;
13075}
13076
13078{
13079 ImGuiContext& g = *GImGui;
13080
13081 ImRect r_outer = GetPopupAllowedExtentRect(window);
13082 if (window->Flags & ImGuiWindowFlags_ChildMenu)
13083 {
13084 // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds.
13085 // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
13086 ImGuiWindow* parent_window = window->ParentWindow;
13087 float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x).
13088 ImRect r_avoid;
13089 if (parent_window->DC.MenuBarAppending)
13090 r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field
13091 else
13092 r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX);
13093 return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
13094 }
13095 if (window->Flags & ImGuiWindowFlags_Popup)
13096 {
13097 return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, ImRect(window->Pos, window->Pos), ImGuiPopupPositionPolicy_Default); // Ideally we'd disable r_avoid here
13098 }
13099 if (window->Flags & ImGuiWindowFlags_Tooltip)
13100 {
13101 // Position tooltip (always follows mouse + clamp within outer boundaries)
13102 // FIXME:
13103 // - Too many paths. One problem is that FindBestWindowPosForPopupEx() doesn't allow passing a suggested position (so touch screen path doesn't use it by default).
13104 // - Drag and drop tooltips are not using this path either: BeginTooltipEx() manually sets their position.
13105 // - Require some tidying up. In theory we could handle both cases in same location, but requires a bit of shuffling
13106 // as drag and drop tooltips are calling SetNextWindowPos() leading to 'window_pos_set_by_api' being set in Begin().
13107 IM_ASSERT(g.CurrentWindow == window);
13108 const float scale = g.Style.MouseCursorScale;
13109 const ImVec2 ref_pos = NavCalcPreferredRefPos();
13110
13112 {
13113 ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET_TOUCH * scale - (TOOLTIP_DEFAULT_PIVOT_TOUCH * window->Size);
13114 if (r_outer.Contains(ImRect(tooltip_pos, tooltip_pos + window->Size)))
13115 return tooltip_pos;
13116 }
13117
13118 ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET_MOUSE * scale;
13119 ImRect r_avoid;
13121 r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
13122 else
13123 r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * scale, ref_pos.y + 24 * scale); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important.
13124 //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255, 0, 255, 255));
13125
13126 return FindBestWindowPosForPopupEx(tooltip_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip);
13127 }
13128 IM_ASSERT(0);
13129 return window->Pos;
13130}
13131
13132//-----------------------------------------------------------------------------
13133// [SECTION] WINDOW FOCUS
13134//----------------------------------------------------------------------------
13135// - SetWindowFocus()
13136// - SetNextWindowFocus()
13137// - IsWindowFocused()
13138// - UpdateWindowInFocusOrderList() [Internal]
13139// - BringWindowToFocusFront() [Internal]
13140// - BringWindowToDisplayFront() [Internal]
13141// - BringWindowToDisplayBack() [Internal]
13142// - BringWindowToDisplayBehind() [Internal]
13143// - FindWindowDisplayIndex() [Internal]
13144// - FocusWindow() [Internal]
13145// - FocusTopMostWindowUnderOne() [Internal]
13146//-----------------------------------------------------------------------------
13147
13149{
13151}
13152
13153void ImGui::SetWindowFocus(const char* name)
13154{
13155 if (name)
13156 {
13157 if (ImGuiWindow* window = FindWindowByName(name))
13158 FocusWindow(window);
13159 }
13160 else
13161 {
13162 FocusWindow(NULL);
13163 }
13164}
13165
13167{
13168 ImGuiContext& g = *GImGui;
13170}
13171
13172// Similar to IsWindowHovered()
13174{
13175 ImGuiContext& g = *GImGui;
13176 ImGuiWindow* ref_window = g.NavWindow;
13177 ImGuiWindow* cur_window = g.CurrentWindow;
13178
13179 if (ref_window == NULL)
13180 return false;
13181 if (flags & ImGuiFocusedFlags_AnyWindow)
13182 return true;
13183
13184 IM_ASSERT(cur_window); // Not inside a Begin()/End()
13185 const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0;
13186 const bool dock_hierarchy = (flags & ImGuiFocusedFlags_DockHierarchy) != 0;
13187 if (flags & ImGuiHoveredFlags_RootWindow)
13188 cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy, dock_hierarchy);
13189
13191 return IsWindowChildOf(ref_window, cur_window, popup_hierarchy, dock_hierarchy);
13192 else
13193 return (ref_window == cur_window);
13194}
13195
13197{
13198 ImGuiContext& g = *GImGui;
13199 IM_UNUSED(g);
13200 int order = window->FocusOrder;
13201 IM_ASSERT(window->RootWindow == window); // No child window (not testing _ChildWindow because of docking)
13202 IM_ASSERT(g.WindowsFocusOrder[order] == window);
13203 return order;
13204}
13205
13206static void ImGui::UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags)
13207{
13208 ImGuiContext& g = *GImGui;
13209
13210 const bool new_is_explicit_child = (new_flags & ImGuiWindowFlags_ChildWindow) != 0 && ((new_flags & ImGuiWindowFlags_Popup) == 0 || (new_flags & ImGuiWindowFlags_ChildMenu) != 0);
13211 const bool child_flag_changed = new_is_explicit_child != window->IsExplicitChild;
13212 if ((just_created || child_flag_changed) && !new_is_explicit_child)
13213 {
13215 g.WindowsFocusOrder.push_back(window);
13216 window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1);
13217 }
13218 else if (!just_created && child_flag_changed && new_is_explicit_child)
13219 {
13220 IM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window);
13221 for (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++)
13222 g.WindowsFocusOrder[n]->FocusOrder--;
13224 window->FocusOrder = -1;
13225 }
13226 window->IsExplicitChild = new_is_explicit_child;
13227}
13228
13230{
13231 ImGuiContext& g = *GImGui;
13232 IM_ASSERT(window == window->RootWindow);
13233
13234 const int cur_order = window->FocusOrder;
13235 IM_ASSERT(g.WindowsFocusOrder[cur_order] == window);
13236 if (g.WindowsFocusOrder.back() == window)
13237 return;
13238
13239 const int new_order = g.WindowsFocusOrder.Size - 1;
13240 for (int n = cur_order; n < new_order; n++)
13241 {
13242 g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1];
13243 g.WindowsFocusOrder[n]->FocusOrder--;
13244 IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n);
13245 }
13246 g.WindowsFocusOrder[new_order] = window;
13247 window->FocusOrder = (short)new_order;
13248}
13249
13250// Note technically focus related but rather adjacent and close to BringWindowToFocusFront()
13252{
13253 ImGuiContext& g = *GImGui;
13254 ImGuiWindow* current_front_window = g.Windows.back();
13255 if (current_front_window == window || current_front_window->RootWindowDockTree == window) // Cheap early out (could be better)
13256 return;
13257 for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window
13258 if (g.Windows[i] == window)
13259 {
13260 memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*));
13261 g.Windows[g.Windows.Size - 1] = window;
13262 break;
13263 }
13264}
13265
13267{
13268 ImGuiContext& g = *GImGui;
13269 if (g.Windows[0] == window)
13270 return;
13271 for (int i = 0; i < g.Windows.Size; i++)
13272 if (g.Windows[i] == window)
13273 {
13274 memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));
13275 g.Windows[0] = window;
13276 break;
13277 }
13278}
13279
13281{
13282 IM_ASSERT(window != NULL && behind_window != NULL);
13283 ImGuiContext& g = *GImGui;
13284 window = window->RootWindow;
13285 behind_window = behind_window->RootWindow;
13286 int pos_wnd = FindWindowDisplayIndex(window);
13287 int pos_beh = FindWindowDisplayIndex(behind_window);
13288 if (pos_wnd < pos_beh)
13289 {
13290 size_t copy_bytes = (pos_beh - pos_wnd - 1) * sizeof(ImGuiWindow*);
13291 memmove(&g.Windows.Data[pos_wnd], &g.Windows.Data[pos_wnd + 1], copy_bytes);
13292 g.Windows[pos_beh - 1] = window;
13293 }
13294 else
13295 {
13296 size_t copy_bytes = (pos_wnd - pos_beh) * sizeof(ImGuiWindow*);
13297 memmove(&g.Windows.Data[pos_beh + 1], &g.Windows.Data[pos_beh], copy_bytes);
13298 g.Windows[pos_beh] = window;
13299 }
13300}
13301
13303{
13304 ImGuiContext& g = *GImGui;
13305 return g.Windows.index_from_ptr(g.Windows.find(window));
13306}
13307
13308// Moving window to front of display and set focus (which happens to be back of our sorted list)
13310{
13311 ImGuiContext& g = *GImGui;
13312
13313 // Modal check?
13314 if ((flags & ImGuiFocusRequestFlags_UnlessBelowModal) && (g.NavWindow != window)) // Early out in common case.
13315 if (ImGuiWindow* blocking_modal = FindBlockingModal(window))
13316 {
13317 // This block would typically be reached in two situations:
13318 // - API call to FocusWindow() with a window under a modal and ImGuiFocusRequestFlags_UnlessBelowModal flag.
13319 // - User clicking on void or anything behind a modal while a modal is open (window == NULL)
13320 IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "<NULL>", blocking_modal->Name);
13321 if (window && window == window->RootWindow && (window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0)
13322 BringWindowToDisplayBehind(window, blocking_modal); // Still bring right under modal. (FIXME: Could move in focus list too?)
13323 ClosePopupsOverWindow(GetTopMostPopupModal(), false); // Note how we need to use GetTopMostPopupModal() aad NOT blocking_modal, to handle nested modals
13324 return;
13325 }
13326
13327 // Find last focused child (if any) and focus it instead.
13328 if ((flags & ImGuiFocusRequestFlags_RestoreFocusedChild) && window != NULL)
13329 window = NavRestoreLastChildNavWindow(window);
13330
13331 // Apply focus
13332 if (g.NavWindow != window)
13333 {
13334 SetNavWindow(window);
13335 if (window && g.NavHighlightItemUnderNav)
13336 g.NavMousePosDirty = true;
13337 g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
13339 SetNavFocusScope(window ? window->NavRootFocusScopeId : 0);
13340 g.NavIdIsAlive = false;
13342
13343 // Close popups if any
13344 ClosePopupsOverWindow(window, false);
13345 }
13346
13347 // Move the root window to the top of the pile
13348 IM_ASSERT(window == NULL || window->RootWindowDockTree != NULL);
13349 ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL;
13350 ImGuiWindow* display_front_window = window ? window->RootWindowDockTree : NULL;
13351 ImGuiDockNode* dock_node = window ? window->DockNode : NULL;
13352 bool active_id_window_is_dock_node_host = (g.ActiveIdWindow && dock_node && dock_node->HostWindow == g.ActiveIdWindow);
13353
13354 // Steal active widgets. Some of the cases it triggers includes:
13355 // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run.
13356 // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId)
13357 // - Using dock host items (tab, collapse button) can trigger this before we redirect the ActiveIdWindow toward the child window.
13358 if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window)
13359 if (!g.ActiveIdNoClearOnFocusLoss && !active_id_window_is_dock_node_host)
13360 ClearActiveID();
13361
13362 // Passing NULL allow to disable keyboard focus
13363 if (!window)
13364 return;
13365 window->LastFrameJustFocused = g.FrameCount;
13366
13367 // Select in dock node
13368 // For #2304 we avoid applying focus immediately before the tabbar is visible.
13369 //if (dock_node && dock_node->TabBar)
13370 // dock_node->TabBar->SelectedTabId = dock_node->TabBar->NextSelectedTabId = window->TabId;
13371
13372 // Bring to front
13373 BringWindowToFocusFront(focus_front_window);
13374 if (((window->Flags | focus_front_window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0)
13375 BringWindowToDisplayFront(display_front_window);
13376}
13377
13378void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags)
13379{
13380 ImGuiContext& g = *GImGui;
13381 int start_idx = g.WindowsFocusOrder.Size - 1;
13382 if (under_this_window != NULL)
13383 {
13384 // Aim at root window behind us, if we are in a child window that's our own root (see #4640)
13385 int offset = -1;
13386 while (under_this_window->Flags & ImGuiWindowFlags_ChildWindow)
13387 {
13388 under_this_window = under_this_window->ParentWindow;
13389 offset = 0;
13390 }
13391 start_idx = FindWindowFocusIndex(under_this_window) + offset;
13392 }
13393 for (int i = start_idx; i >= 0; i--)
13394 {
13395 // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user.
13396 ImGuiWindow* window = g.WindowsFocusOrder[i];
13397 if (window == ignore_window || !window->WasActive)
13398 continue;
13399 if (filter_viewport != NULL && window->Viewport != filter_viewport)
13400 continue;
13402 {
13403 // FIXME-DOCK: When ImGuiFocusRequestFlags_RestoreFocusedChild is set...
13404 // This is failing (lagging by one frame) for docked windows.
13405 // If A and B are docked into window and B disappear, at the NewFrame() call site window->NavLastChildNavWindow will still point to B.
13406 // We might leverage the tab order implicitly stored in window->DockNodeAsHost->TabBar (essentially the 'most_recently_selected_tab' code in tab bar will do that but on next update)
13407 // to tell which is the "previous" window. Or we may leverage 'LastFrameFocused/LastFrameJustFocused' and have this function handle child window itself?
13408 FocusWindow(window, flags);
13409 return;
13410 }
13411 }
13412 FocusWindow(NULL, flags);
13413}
13414
13415//-----------------------------------------------------------------------------
13416// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
13417//-----------------------------------------------------------------------------
13418
13419// FIXME-NAV: The existence of SetNavID vs SetFocusID vs FocusWindow() needs to be clarified/reworked.
13420// In our terminology those should be interchangeable, yet right now this is super confusing.
13421// Those two functions are merely a legacy artifact, so at minimum naming should be clarified.
13422
13424{
13425 ImGuiContext& g = *GImGui;
13427 visible = true;
13428 g.NavCursorVisible = visible;
13429}
13430
13431// (was called NavRestoreHighlightAfterMove() before 1.91.4)
13433{
13434 ImGuiContext& g = *GImGui;
13436 g.NavCursorVisible = true;
13438}
13439
13441{
13442 ImGuiContext& g = *GImGui;
13443 if (g.NavWindow != window)
13444 {
13445 IMGUI_DEBUG_LOG_FOCUS("[focus] SetNavWindow(\"%s\")\n", window ? window->Name : "<NULL>");
13446 g.NavWindow = window;
13448 }
13451}
13452
13454{
13455 ImGuiContext& g = *GImGui;
13458}
13459
13461{
13462 ImGuiContext& g = *GImGui;
13464}
13465
13466void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
13467{
13468 ImGuiContext& g = *GImGui;
13469 IM_ASSERT(g.NavWindow != NULL);
13470 IM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu);
13471 g.NavId = id;
13472 g.NavLayer = nav_layer;
13473 SetNavFocusScope(focus_scope_id);
13474 g.NavWindow->NavLastIds[nav_layer] = id;
13475 g.NavWindow->NavRectRel[nav_layer] = rect_rel;
13476
13477 // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it)
13480}
13481
13483{
13484 ImGuiContext& g = *GImGui;
13485 IM_ASSERT(id != 0);
13486
13487 if (g.NavWindow != window)
13488 SetNavWindow(window);
13489
13490 // Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and g.CurrentFocusScopeId are valid.
13491 // Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text)
13492 const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
13493 g.NavId = id;
13494 g.NavLayer = nav_layer;
13496 window->NavLastIds[nav_layer] = id;
13497 if (g.LastItemData.ID == id)
13498 window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect);
13499
13501 g.NavHighlightItemUnderNav = true;
13502 else if (g.IO.ConfigNavCursorVisibleAuto)
13503 g.NavCursorVisible = false;
13504
13505 // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it)
13508}
13509
13510static ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy)
13511{
13512 if (ImFabs(dx) > ImFabs(dy))
13513 return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
13514 return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
13515}
13516
13517static float inline NavScoreItemDistInterval(float cand_min, float cand_max, float curr_min, float curr_max)
13518{
13519 if (cand_max < curr_min)
13520 return cand_max - curr_min;
13521 if (curr_max < cand_min)
13522 return cand_min - curr_max;
13523 return 0.0f;
13524}
13525
13526// Scoring function for keyboard/gamepad directional navigation. Based on https://gist.github.com/rygorous/6981057
13528{
13529 ImGuiContext& g = *GImGui;
13530 ImGuiWindow* window = g.CurrentWindow;
13531 if (g.NavLayer != window->DC.NavLayerCurrent)
13532 return false;
13533
13534 // FIXME: Those are not good variables names
13535 ImRect cand = g.LastItemData.NavRect; // Current item nav rectangle
13536 const ImRect curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width)
13538
13539 // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring
13540 if (window->ParentWindow == g.NavWindow)
13541 {
13543 if (!window->ClipRect.Overlaps(cand))
13544 return false;
13545 cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window
13546 }
13547
13548 // Compute distance between boxes
13549 // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.
13550 float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
13551 float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items
13552 if (dby != 0.0f && dbx != 0.0f)
13553 dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
13554 float dist_box = ImFabs(dbx) + ImFabs(dby);
13555
13556 // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter)
13557 float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
13558 float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
13559 float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee)
13560
13561 // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance
13562 ImGuiDir quadrant;
13563 float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
13564 if (dbx != 0.0f || dby != 0.0f)
13565 {
13566 // For non-overlapping boxes, use distance between boxes
13567 // FIXME-NAV: Quadrant may be incorrect because of (1) dbx bias and (2) curr.Max.y bias applied by NavBiasScoringRect() where typically curr.Max.y==curr.Min.y
13568 // One typical case where this happens, with style.WindowMenuButtonPosition == ImGuiDir_Right, pressing Left to navigate from Close to Collapse tends to fail.
13569 // Also see #6344. Calling ImGetDirQuadrantFromDelta() with unbiased values may be good but side-effects are plenty.
13570 dax = dbx;
13571 day = dby;
13572 dist_axial = dist_box;
13573 quadrant = ImGetDirQuadrantFromDelta(dbx, dby);
13574 }
13575 else if (dcx != 0.0f || dcy != 0.0f)
13576 {
13577 // For overlapping boxes with different centers, use distance between centers
13578 dax = dcx;
13579 day = dcy;
13580 dist_axial = dist_center;
13581 quadrant = ImGetDirQuadrantFromDelta(dcx, dcy);
13582 }
13583 else
13584 {
13585 // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter)
13586 quadrant = (g.LastItemData.ID < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
13587 }
13588
13589 const ImGuiDir move_dir = g.NavMoveDir;
13590#if IMGUI_DEBUG_NAV_SCORING
13591 char buf[200];
13592 if (g.IO.KeyCtrl) // Hold CTRL to preview score in matching quadrant. CTRL+Arrow to rotate.
13593 {
13594 if (quadrant == move_dir)
13595 {
13596 ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
13597 ImDrawList* draw_list = GetForegroundDrawList(window);
13598 draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 80));
13599 draw_list->AddRectFilled(cand.Min, cand.Min + CalcTextSize(buf), IM_COL32(255, 0, 0, 200));
13600 draw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf);
13601 }
13602 }
13603 const bool debug_hovering = IsMouseHoveringRect(cand.Min, cand.Max);
13604 const bool debug_tty = (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_Space));
13605 if (debug_hovering || debug_tty)
13606 {
13607 ImFormatString(buf, IM_ARRAYSIZE(buf),
13608 "d-box (%7.3f,%7.3f) -> %7.3f\nd-center (%7.3f,%7.3f) -> %7.3f\nd-axial (%7.3f,%7.3f) -> %7.3f\nnav %c, quadrant %c",
13609 dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "-WENS"[move_dir+1], "-WENS"[quadrant+1]);
13610 if (debug_hovering)
13611 {
13612 ImDrawList* draw_list = GetForegroundDrawList(window);
13613 draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255, 200, 0, 100));
13614 draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255, 255, 0, 200));
13615 draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40, 0, 0, 200));
13616 draw_list->AddText(cand.Max, ~0U, buf);
13617 }
13618 if (debug_tty) { IMGUI_DEBUG_LOG_NAV("id 0x%08X\n%s\n", g.LastItemData.ID, buf); }
13619 }
13620#endif
13621
13622 // Is it in the quadrant we're interested in moving to?
13623 bool new_best = false;
13624 if (quadrant == move_dir)
13625 {
13626 // Does it beat the current best candidate?
13627 if (dist_box < result->DistBox)
13628 {
13629 result->DistBox = dist_box;
13630 result->DistCenter = dist_center;
13631 return true;
13632 }
13633 if (dist_box == result->DistBox)
13634 {
13635 // Try using distance between center points to break ties
13636 if (dist_center < result->DistCenter)
13637 {
13638 result->DistCenter = dist_center;
13639 new_best = true;
13640 }
13641 else if (dist_center == result->DistCenter)
13642 {
13643 // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
13644 // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index),
13645 // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis.
13646 if (((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
13647 new_best = true;
13648 }
13649 }
13650 }
13651
13652 // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches
13653 // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)
13654 // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too.
13655 // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward.
13656 // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
13657 if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match
13659 if ((move_dir == ImGuiDir_Left && dax < 0.0f) || (move_dir == ImGuiDir_Right && dax > 0.0f) || (move_dir == ImGuiDir_Up && day < 0.0f) || (move_dir == ImGuiDir_Down && day > 0.0f))
13660 {
13661 result->DistAxial = dist_axial;
13662 new_best = true;
13663 }
13664
13665 return new_best;
13666}
13667
13669{
13670 ImGuiContext& g = *GImGui;
13671 ImGuiWindow* window = g.CurrentWindow;
13672 result->Window = window;
13673 result->ID = g.LastItemData.ID;
13675 result->ItemFlags = g.LastItemData.ItemFlags;
13676 result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect);
13678 {
13680 result->SelectionUserData = g.NextItemData.SelectionUserData; // INTENTIONAL: At this point this field is not cleared in NextItemData. Avoid unnecessary copy to LastItemData.
13681 }
13682}
13683
13684// True when current work location may be scrolled horizontally when moving left / right.
13685// This is generally always true UNLESS within a column. We don't have a vertical equivalent.
13687{
13688 ImGuiContext& g = *GImGui;
13689 ImGuiWindow* window = g.CurrentWindow;
13690 window->DC.NavIsScrollPushableX = (g.CurrentTable == NULL && window->DC.CurrentColumns == NULL);
13691}
13692
13693// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
13694// This is called after LastItemData is set, but NextItemData is also still valid.
13696{
13697 ImGuiContext& g = *GImGui;
13698 ImGuiWindow* window = g.CurrentWindow;
13699 const ImGuiID id = g.LastItemData.ID;
13700 const ImGuiItemFlags item_flags = g.LastItemData.ItemFlags;
13701
13702 // When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221)
13703 if (window->DC.NavIsScrollPushableX == false)
13704 {
13707 }
13708 const ImRect nav_bb = g.LastItemData.NavRect;
13709
13710 // Process Init Request
13711 if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent && (item_flags & ImGuiItemFlags_Disabled) == 0)
13712 {
13713 // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
13714 const bool candidate_for_nav_default_focus = (item_flags & ImGuiItemFlags_NoNavDefaultFocus) == 0;
13715 if (candidate_for_nav_default_focus || g.NavInitResult.ID == 0)
13716 {
13718 }
13719 if (candidate_for_nav_default_focus)
13720 {
13721 g.NavInitRequest = false; // Found a match, clear request
13723 }
13724 }
13725
13726 // Process Move Request (scoring for navigation)
13727 // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRect + scoring from a rect wrapped according to current wrapping policy)
13728 if (g.NavMoveScoringItems && (item_flags & ImGuiItemFlags_Disabled) == 0)
13729 {
13731 {
13732 const bool is_tabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) != 0;
13733 if (is_tabbing)
13734 {
13736 }
13737 else if (g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId))
13738 {
13739 ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
13740 if (NavScoreItem(result))
13741 NavApplyItemToResult(result);
13742
13743 // Features like PageUp/PageDown need to maintain a separate score for the visible set of items.
13744 const float VISIBLE_RATIO = 0.70f;
13746 if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO)
13749 }
13750 }
13751 }
13752
13753 // Update information for currently focused/navigated item
13754 if (g.NavId == id)
13755 {
13756 if (g.NavWindow != window)
13757 SetNavWindow(window); // Always refresh g.NavWindow, because some operations such as FocusItem() may not have a window.
13758 g.NavLayer = window->DC.NavLayerCurrent;
13759 SetNavFocusScope(g.CurrentFocusScopeId); // Will set g.NavFocusScopeId AND store g.NavFocusScopePath
13761 g.NavIdIsAlive = true;
13763 {
13765 g.NavLastValidSelectionUserData = g.NextItemData.SelectionUserData; // INTENTIONAL: At this point this field is not cleared in NextItemData. Avoid unnecessary copy to LastItemData.
13766 }
13767 window->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position)
13768 }
13769}
13770
13771// Handle "scoring" of an item for a tabbing/focusing request initiated by NavUpdateCreateTabbingRequest().
13772// Note that SetKeyboardFocusHere() API calls are considered tabbing requests!
13773// - Case 1: no nav/active id: set result to first eligible item, stop storing.
13774// - Case 2: tab forward: on ref id set counter, on counter elapse store result
13775// - Case 3: tab forward wrap: set result to first eligible item (preemptively), on ref id set counter, on next frame if counter hasn't elapsed store result. // FIXME-TABBING: Could be done as a next-frame forwarded request
13776// - Case 4: tab backward: store all results, on ref id pick prev, stop storing
13777// - Case 5: tab backward wrap: store all results, on ref id if no result keep storing until last // FIXME-TABBING: Could be done as next-frame forwarded requested
13779{
13780 ImGuiContext& g = *GImGui;
13781
13782 if ((move_flags & ImGuiNavMoveFlags_FocusApi) == 0)
13783 {
13785 return;
13787 return;
13788 }
13789
13790 // - Can always land on an item when using API call.
13791 // - Tabbing with _NavEnableKeyboard (space/enter/arrows): goes through every item.
13792 // - Tabbing without _NavEnableKeyboard: goes through inputable items only.
13793 bool can_stop;
13794 if (move_flags & ImGuiNavMoveFlags_FocusApi)
13795 can_stop = true;
13796 else
13797 can_stop = (item_flags & ImGuiItemFlags_NoTabStop) == 0 && ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) || (item_flags & ImGuiItemFlags_Inputable));
13798
13799 // Always store in NavMoveResultLocal (unlike directional request which uses NavMoveResultOther on sibling/flattened windows)
13801 if (g.NavTabbingDir == +1)
13802 {
13803 // Tab Forward or SetKeyboardFocusHere() with >= 0
13804 if (can_stop && g.NavTabbingResultFirst.ID == 0)
13806 if (can_stop && g.NavTabbingCounter > 0 && --g.NavTabbingCounter == 0)
13808 else if (g.NavId == id)
13809 g.NavTabbingCounter = 1;
13810 }
13811 else if (g.NavTabbingDir == -1)
13812 {
13813 // Tab Backward
13814 if (g.NavId == id)
13815 {
13816 if (result->ID)
13817 {
13818 g.NavMoveScoringItems = false;
13820 }
13821 }
13822 else if (can_stop)
13823 {
13824 // Keep applying until reaching NavId
13825 NavApplyItemToResult(result);
13826 }
13827 }
13828 else if (g.NavTabbingDir == 0)
13829 {
13830 if (can_stop && g.NavId == id)
13832 if (can_stop && g.NavTabbingResultFirst.ID == 0) // Tab init
13834 }
13835}
13836
13838{
13839 ImGuiContext& g = *GImGui;
13840 return g.NavMoveScoringItems && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
13841}
13842
13843// FIXME: ScoringRect is not set
13844void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)
13845{
13846 ImGuiContext& g = *GImGui;
13847 IM_ASSERT(g.NavWindow != NULL);
13848 //IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestSubmit: dir %c, window \"%s\"\n", "-WENS"[move_dir + 1], g.NavWindow->Name);
13849
13850 if (move_flags & ImGuiNavMoveFlags_IsTabbing)
13852
13854 g.NavMoveDir = move_dir;
13855 g.NavMoveDirForDebug = move_dir;
13856 g.NavMoveClipDir = clip_dir;
13857 g.NavMoveFlags = move_flags;
13858 g.NavMoveScrollFlags = scroll_flags;
13859 g.NavMoveForwardToNextFrame = false;
13860 g.NavMoveKeyMods = (move_flags & ImGuiNavMoveFlags_FocusApi) ? 0 : g.IO.KeyMods;
13864 g.NavTabbingCounter = 0;
13867}
13868
13870{
13871 ImGuiContext& g = *GImGui;
13872 g.NavMoveScoringItems = false; // Ensure request doesn't need more processing
13873 NavApplyItemToResult(result);
13875}
13876
13877// Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsToParent
13879{
13880 ImGuiContext& g = *GImGui;
13881 g.NavMoveScoringItems = false;
13882 g.LastItemData.ID = tree_node_data->ID;
13883 g.LastItemData.ItemFlags = tree_node_data->ItemFlags & ~ImGuiItemFlags_HasSelectionUserData; // Losing SelectionUserData, recovered next-frame (cheaper).
13884 g.LastItemData.NavRect = tree_node_data->NavRect;
13885 NavApplyItemToResult(result); // Result this instead of implementing a NavApplyPastTreeNodeToResult()
13888}
13889
13891{
13892 ImGuiContext& g = *GImGui;
13895}
13896
13897// Forward will reuse the move request again on the next frame (generally with modifications done to it)
13898void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)
13899{
13900 ImGuiContext& g = *GImGui;
13904 g.NavMoveDir = move_dir;
13905 g.NavMoveClipDir = clip_dir;
13907 g.NavMoveScrollFlags = scroll_flags;
13908}
13909
13910// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire
13911// popup is assembled and in case of appended popups it is not clear which EndPopup() call is final.
13913{
13914 ImGuiContext& g = *GImGui;
13915 IM_ASSERT((wrap_flags & ImGuiNavMoveFlags_WrapMask_ ) != 0 && (wrap_flags & ~ImGuiNavMoveFlags_WrapMask_) == 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY
13916
13917 // In theory we should test for NavMoveRequestButNoResultYet() but there's no point doing it:
13918 // as NavEndFrame() will do the same test. It will end up calling NavUpdateCreateWrappingRequest().
13919 if (g.NavWindow == window && g.NavMoveScoringItems && g.NavLayer == ImGuiNavLayer_Main)
13920 g.NavMoveFlags = (g.NavMoveFlags & ~ImGuiNavMoveFlags_WrapMask_) | wrap_flags;
13921}
13922
13923// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0).
13924// This way we could find the last focused window among our children. It would be much less confusing this way?
13926{
13927 ImGuiWindow* parent = nav_window;
13928 while (parent && parent->RootWindow != parent && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
13929 parent = parent->ParentWindow;
13930 if (parent && parent != nav_window)
13931 parent->NavLastChildNavWindow = nav_window;
13932}
13933
13934// Restore the last focused child.
13935// Call when we are expected to land on the Main Layer (0) after FocusWindow()
13937{
13939 return window->NavLastChildNavWindow;
13940 if (window->DockNodeAsHost && window->DockNodeAsHost->TabBar)
13942 return tab->Window;
13943 return window;
13944}
13945
13947{
13948 ImGuiContext& g = *GImGui;
13949 if (layer == ImGuiNavLayer_Main)
13950 {
13951 ImGuiWindow* prev_nav_window = g.NavWindow;
13952 g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow); // FIXME-NAV: Should clear ongoing nav requests?
13954 if (prev_nav_window)
13955 IMGUI_DEBUG_LOG_FOCUS("[focus] NavRestoreLayer: from \"%s\" to SetNavWindow(\"%s\")\n", prev_nav_window->Name, g.NavWindow->Name);
13956 }
13957 ImGuiWindow* window = g.NavWindow;
13958 if (window->NavLastIds[layer] != 0)
13959 {
13960 SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]);
13961 }
13962 else
13963 {
13964 g.NavLayer = layer;
13965 NavInitWindow(window, true);
13966 }
13967}
13968
13970{
13971 ImGuiContext& g = *GImGui;
13973 if (g.NavAnyRequest)
13974 IM_ASSERT(g.NavWindow != NULL);
13975}
13976
13977// This needs to be called before we submit any widget (aka in or before Begin)
13978void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
13979{
13980 // FIXME: ChildWindow test here is wrong for docking
13981 ImGuiContext& g = *GImGui;
13982 IM_ASSERT(window == g.NavWindow);
13983
13984 if (window->Flags & ImGuiWindowFlags_NoNavInputs)
13985 {
13986 g.NavId = 0;
13988 return;
13989 }
13990
13991 bool init_for_nav = false;
13992 if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
13993 init_for_nav = true;
13994 IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
13995 if (init_for_nav)
13996 {
13997 SetNavID(0, g.NavLayer, window->NavRootFocusScopeId, ImRect());
13998 g.NavInitRequest = true;
13999 g.NavInitRequestFromMove = false;
14000 g.NavInitResult.ID = 0;
14002 }
14003 else
14004 {
14005 g.NavId = window->NavLastIds[0];
14007 }
14008}
14009
14011{
14012 ImGuiContext& g = *GImGui;
14013 ImGuiWindow* window = g.NavWindow;
14014 const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID;
14015
14016 // Testing for !activated_shortcut here could in theory be removed if we decided that activating a remote shortcut altered one of the g.NavDisableXXX flag.
14017 if ((!g.NavCursorVisible || !g.NavHighlightItemUnderNav || !window) && !activated_shortcut)
14019 else
14020 return ImGuiInputSource_Keyboard; // or Nav in general
14021}
14022
14024{
14025 ImGuiContext& g = *GImGui;
14026 ImGuiWindow* window = g.NavWindow;
14028
14029 const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID;
14030
14031 // Testing for !activated_shortcut here could in theory be removed if we decided that activating a remote shortcut altered one of the g.NavDisableXXX flag.
14032 if (source == ImGuiInputSource_Mouse)
14033 {
14034 // Mouse (we need a fallback in case the mouse becomes invalid after being used)
14035 // The +1.0f offset when stored by OpenPopupEx() allows reopening this or another popup (same or another mouse button) while not moving the mouse, it is pretty standard.
14036 // In theory we could move that +1.0f offset in OpenPopupEx()
14038 return ImVec2(p.x + 1.0f, p.y);
14039 }
14040 else
14041 {
14042 // When navigation is active and mouse is disabled, pick a position around the bottom left of the currently navigated item
14043 ImRect ref_rect;
14044 if (activated_shortcut)
14045 ref_rect = g.LastItemData.NavRect;
14046 else
14047 ref_rect = WindowRectRelToAbs(window, window->NavRectRel[g.NavLayer]);
14048
14049 // Take account of upcoming scrolling (maybe set mouse pos should be done in EndFrame?)
14050 if (window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x != FLT_MAX || window->ScrollTarget.y != FLT_MAX))
14051 {
14052 ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
14053 ref_rect.Translate(window->Scroll - next_scroll);
14054 }
14055 ImVec2 pos = ImVec2(ref_rect.Min.x + ImMin(g.Style.FramePadding.x * 4, ref_rect.GetWidth()), ref_rect.Max.y - ImMin(g.Style.FramePadding.y, ref_rect.GetHeight()));
14056 ImGuiViewport* viewport = window->Viewport;
14057 return ImTrunc(ImClamp(pos, viewport->Pos, viewport->Pos + viewport->Size)); // ImTrunc() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta.
14058 }
14059}
14060
14062{
14063 ImGuiContext& g = *GImGui;
14064 float repeat_delay, repeat_rate;
14065 GetTypematicRepeatRate(ImGuiInputFlags_RepeatRateNavTweak, &repeat_delay, &repeat_rate);
14066
14067 ImGuiKey key_less, key_more;
14069 {
14072 }
14073 else
14074 {
14075 key_less = (axis == ImGuiAxis_X) ? ImGuiKey_LeftArrow : ImGuiKey_UpArrow;
14076 key_more = (axis == ImGuiAxis_X) ? ImGuiKey_RightArrow : ImGuiKey_DownArrow;
14077 }
14078 float amount = (float)GetKeyPressedAmount(key_more, repeat_delay, repeat_rate) - (float)GetKeyPressedAmount(key_less, repeat_delay, repeat_rate);
14079 if (amount != 0.0f && IsKeyDown(key_less) && IsKeyDown(key_more)) // Cancel when opposite directions are held, regardless of repeat phase
14080 amount = 0.0f;
14081 return amount;
14082}
14083
14084static void ImGui::NavUpdate()
14085{
14086 ImGuiContext& g = *GImGui;
14087 ImGuiIO& io = g.IO;
14088
14089 io.WantSetMousePos = false;
14090 //if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG_NAV("[nav] NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
14091
14092 // Set input source based on which keys are last pressed (as some features differs when used with Gamepad vs Keyboard)
14093 // FIXME-NAV: Now that keys are separated maybe we can get rid of NavInputSource?
14094 const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
14096 if (nav_gamepad_active)
14097 for (ImGuiKey key : nav_gamepad_keys_to_change_source)
14098 if (IsKeyDown(key))
14100 const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
14102 if (nav_keyboard_active)
14103 for (ImGuiKey key : nav_keyboard_keys_to_change_source)
14104 if (IsKeyDown(key))
14106
14107 // Process navigation init request (select first/default focus)
14108 g.NavJustMovedToId = 0;
14110 if (g.NavInitResult.ID != 0)
14112 g.NavInitRequest = false;
14113 g.NavInitRequestFromMove = false;
14114 g.NavInitResult.ID = 0;
14115
14116 // Process navigation move request
14117 if (g.NavMoveSubmitted)
14119 g.NavTabbingCounter = 0;
14121 if (g.NavCursorHideFrames > 0)
14122 if (--g.NavCursorHideFrames == 0)
14123 g.NavCursorVisible = true;
14124
14125 // Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling)
14126 bool set_mouse_pos = false;
14127 if (g.NavMousePosDirty && g.NavIdIsAlive)
14129 set_mouse_pos = true;
14130 g.NavMousePosDirty = false;
14132
14133 // Store our return window (for returning from Menu Layer to Main Layer) and clear it as soon as we step back in our own Layer 0
14134 if (g.NavWindow)
14138
14139 // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.)
14141
14142 // Set output flags for user application
14143 io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
14144 io.NavVisible = (io.NavActive && g.NavId != 0 && g.NavCursorVisible) || (g.NavWindowingTarget != NULL);
14145
14146 // Process NavCancel input (to close a popup, get back to parent, clear focus)
14148
14149 // Process manual activation request
14153 {
14154 const bool activate_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Space, ImGuiKeyOwner_NoOwner)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadActivate, ImGuiKeyOwner_NoOwner));
14155 const bool activate_pressed = activate_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Space, 0, ImGuiKeyOwner_NoOwner)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadActivate, 0, ImGuiKeyOwner_NoOwner)));
14156 const bool input_down = (nav_keyboard_active && (IsKeyDown(ImGuiKey_Enter, ImGuiKeyOwner_NoOwner) || IsKeyDown(ImGuiKey_KeypadEnter, ImGuiKeyOwner_NoOwner))) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadInput, ImGuiKeyOwner_NoOwner));
14157 const bool input_pressed = input_down && ((nav_keyboard_active && (IsKeyPressed(ImGuiKey_Enter, 0, ImGuiKeyOwner_NoOwner) || IsKeyPressed(ImGuiKey_KeypadEnter, 0, ImGuiKeyOwner_NoOwner))) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadInput, 0, ImGuiKeyOwner_NoOwner)));
14158 if (g.ActiveId == 0 && activate_pressed)
14159 {
14160 g.NavActivateId = g.NavId;
14162 }
14163 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && input_pressed)
14164 {
14165 g.NavActivateId = g.NavId;
14167 }
14168 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_down || input_down))
14170 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_pressed || input_pressed))
14171 {
14174 }
14175 }
14177 g.NavCursorVisible = false;
14179 g.NavCursorVisible = true;
14180 if (g.NavActivateId != 0)
14182
14183 // Highlight
14184 if (g.NavHighlightActivatedTimer > 0.0f)
14186 if (g.NavHighlightActivatedTimer == 0.0f)
14188
14189 // Process programmatic activation request
14190 // FIXME-NAV: Those should eventually be queued (unlike focus they don't cancel each others)
14191 if (g.NavNextActivateId != 0)
14192 {
14195 }
14196 g.NavNextActivateId = 0;
14197
14198 // Process move requests
14200 if (g.NavMoveDir == ImGuiDir_None)
14203 g.NavIdIsAlive = false;
14204
14205 // Scrolling
14207 {
14208 // *Fallback* manual-scroll with Nav directional keys when window has no navigable item
14209 ImGuiWindow* window = g.NavWindow;
14210 const float scroll_speed = IM_ROUND(window->FontRefSize * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
14211 const ImGuiDir move_dir = g.NavMoveDir;
14212 if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY && move_dir != ImGuiDir_None)
14213 {
14214 if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
14215 SetScrollX(window, ImTrunc(window->Scroll.x + ((move_dir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
14216 if (move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down)
14217 SetScrollY(window, ImTrunc(window->Scroll.y + ((move_dir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
14218 }
14219
14220 // *Normal* Manual scroll with LStick
14221 // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
14222 if (nav_gamepad_active)
14223 {
14225 const float tweak_factor = IsKeyDown(ImGuiKey_NavGamepadTweakSlow) ? 1.0f / 10.0f : IsKeyDown(ImGuiKey_NavGamepadTweakFast) ? 10.0f : 1.0f;
14226 if (scroll_dir.x != 0.0f && window->ScrollbarX)
14227 SetScrollX(window, ImTrunc(window->Scroll.x + scroll_dir.x * scroll_speed * tweak_factor));
14228 if (scroll_dir.y != 0.0f)
14229 SetScrollY(window, ImTrunc(window->Scroll.y + scroll_dir.y * scroll_speed * tweak_factor));
14230 }
14231 }
14232
14233 // Always prioritize mouse highlight if navigation is disabled
14234 if (!nav_keyboard_active && !nav_gamepad_active)
14235 {
14236 g.NavCursorVisible = false;
14237 g.NavHighlightItemUnderNav = set_mouse_pos = false;
14238 }
14239
14240 // Update mouse position if requested
14241 // (This will take into account the possibility that a Scroll was queued in the window to offset our absolute mouse position before scroll has been applied)
14244
14245 // [DEBUG]
14247#if IMGUI_DEBUG_NAV_RECTS
14248 if (ImGuiWindow* debug_window = g.NavWindow)
14249 {
14250 ImDrawList* draw_list = GetForegroundDrawList(debug_window);
14251 int layer = g.NavLayer; /* for (int layer = 0; layer < 2; layer++)*/ { ImRect r = WindowRectRelToAbs(debug_window, debug_window->NavRectRel[layer]); draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 200, 0, 255)); }
14252 //if (1) { ImU32 col = (!debug_window->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); }
14253 }
14254#endif
14255}
14256
14258{
14259 // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void)
14260 ImGuiContext& g = *GImGui;
14261 if (!g.NavWindow)
14262 return;
14263
14264 ImGuiNavItemData* result = &g.NavInitResult;
14265 if (g.NavId != result->ID)
14266 {
14268 g.NavJustMovedToId = result->ID;
14271 g.NavJustMovedToIsTabbing = false;
14273 }
14274
14275 // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
14276 // FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently.
14277 IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: ApplyResult: NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
14278 SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
14279 g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result
14284}
14285
14286// Bias scoring rect ahead of scoring + update preferred pos (if missing) using source position
14287static void NavBiasScoringRect(ImRect& r, ImVec2& preferred_pos_rel, ImGuiDir move_dir, ImGuiNavMoveFlags move_flags)
14288{
14289 // Bias initial rect
14290 ImGuiContext& g = *GImGui;
14291 const ImVec2 rel_to_abs_offset = g.NavWindow->DC.CursorStartPos;
14292
14293 // Initialize bias on departure if we don't have any. So mouse-click + arrow will record bias.
14294 // - We default to L/U bias, so moving down from a large source item into several columns will land on left-most column.
14295 // - But each successful move sets new bias on one axis, only cleared when using mouse.
14296 if ((move_flags & ImGuiNavMoveFlags_Forwarded) == 0)
14297 {
14298 if (preferred_pos_rel.x == FLT_MAX)
14299 preferred_pos_rel.x = ImMin(r.Min.x + 1.0f, r.Max.x) - rel_to_abs_offset.x;
14300 if (preferred_pos_rel.y == FLT_MAX)
14301 preferred_pos_rel.y = r.GetCenter().y - rel_to_abs_offset.y;
14302 }
14303
14304 // Apply general bias on the other axis
14305 if ((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) && preferred_pos_rel.x != FLT_MAX)
14306 r.Min.x = r.Max.x = preferred_pos_rel.x + rel_to_abs_offset.x;
14307 else if ((move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) && preferred_pos_rel.y != FLT_MAX)
14308 r.Min.y = r.Max.y = preferred_pos_rel.y + rel_to_abs_offset.y;
14309}
14310
14312{
14313 ImGuiContext& g = *GImGui;
14314 ImGuiIO& io = g.IO;
14315 ImGuiWindow* window = g.NavWindow;
14316 const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
14317 const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
14318
14319 if (g.NavMoveForwardToNextFrame && window != NULL)
14320 {
14321 // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)
14322 // (preserve most state, which were already set by the NavMoveRequestForward() function)
14325 IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
14326 }
14327 else
14328 {
14329 // Initiate directional inputs request
14333 if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs))
14334 {
14336 if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadLeft, repeat_mode, ImGuiKeyOwner_NoOwner)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_LeftArrow, repeat_mode, ImGuiKeyOwner_NoOwner)))) { g.NavMoveDir = ImGuiDir_Left; }
14337 if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadRight, repeat_mode, ImGuiKeyOwner_NoOwner)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_RightArrow, repeat_mode, ImGuiKeyOwner_NoOwner)))) { g.NavMoveDir = ImGuiDir_Right; }
14338 if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadUp, repeat_mode, ImGuiKeyOwner_NoOwner)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_UpArrow, repeat_mode, ImGuiKeyOwner_NoOwner)))) { g.NavMoveDir = ImGuiDir_Up; }
14339 if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadDown, repeat_mode, ImGuiKeyOwner_NoOwner)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_DownArrow, repeat_mode, ImGuiKeyOwner_NoOwner)))) { g.NavMoveDir = ImGuiDir_Down; }
14340 }
14342 g.NavScoringNoClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);
14343 }
14344
14345 // Update PageUp/PageDown/Home/End scroll
14346 // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
14347 float scoring_rect_offset_y = 0.0f;
14348 if (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active)
14349 scoring_rect_offset_y = NavUpdatePageUpPageDown();
14350 if (scoring_rect_offset_y != 0.0f)
14351 {
14352 g.NavScoringNoClipRect = window->InnerRect;
14353 g.NavScoringNoClipRect.TranslateY(scoring_rect_offset_y);
14354 }
14355
14356 // [DEBUG] Always send a request when holding CTRL. Hold CTRL + Arrow change the direction.
14357#if IMGUI_DEBUG_NAV_SCORING
14358 //if (io.KeyCtrl && IsKeyPressed(ImGuiKey_C))
14359 // g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3);
14360 if (io.KeyCtrl)
14361 {
14362 if (g.NavMoveDir == ImGuiDir_None)
14366 }
14367#endif
14368
14369 // Submit
14370 g.NavMoveForwardToNextFrame = false;
14371 if (g.NavMoveDir != ImGuiDir_None)
14373
14374 // Moving with no reference triggers an init request (will be used as a fallback if the direction fails to find a match)
14375 if (g.NavMoveSubmitted && g.NavId == 0)
14376 {
14377 IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "<NULL>", g.NavLayer);
14379 g.NavInitResult.ID = 0;
14381 g.NavCursorVisible = true;
14382 }
14383
14384 // When using gamepad, we project the reference nav bounding box into window visible area.
14385 // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling,
14386 // since with gamepad all movements are relative (can't focus a visible object like we can with the mouse).
14387 if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded))
14388 {
14389 bool clamp_x = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapX)) == 0;
14390 bool clamp_y = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapY)) == 0;
14391 ImRect inner_rect_rel = WindowRectAbsToRel(window, ImRect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)));
14392
14393 // Take account of changing scroll to handle triggering a new move request on a scrolling frame. (#6171)
14394 // Otherwise 'inner_rect_rel' would be off on the move result frame.
14395 inner_rect_rel.Translate(CalcNextScrollFromScrollTargetAndClamp(window) - window->Scroll);
14396
14397 if ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
14398 {
14399 IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n");
14400 float pad_x = ImMin(inner_rect_rel.GetWidth(), window->FontRefSize * 0.5f);
14401 float pad_y = ImMin(inner_rect_rel.GetHeight(), window->FontRefSize * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item
14402 inner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -FLT_MAX;
14403 inner_rect_rel.Max.x = clamp_x ? (inner_rect_rel.Max.x - pad_x) : +FLT_MAX;
14404 inner_rect_rel.Min.y = clamp_y ? (inner_rect_rel.Min.y + pad_y) : -FLT_MAX;
14405 inner_rect_rel.Max.y = clamp_y ? (inner_rect_rel.Max.y - pad_y) : +FLT_MAX;
14406 window->NavRectRel[g.NavLayer].ClipWithFull(inner_rect_rel);
14407 g.NavId = 0;
14408 }
14409 }
14410
14411 // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
14412 ImRect scoring_rect;
14413 if (window != NULL)
14414 {
14415 ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
14416 scoring_rect = WindowRectRelToAbs(window, nav_rect_rel);
14417 scoring_rect.TranslateY(scoring_rect_offset_y);
14418 if (g.NavMoveSubmitted)
14420 IM_ASSERT(!scoring_rect.IsInverted()); // Ensure we have a non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem().
14421 //GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
14422 //if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG]
14423 }
14424 g.NavScoringRect = scoring_rect;
14425 //g.NavScoringNoClipRect.Add(scoring_rect);
14426}
14427
14429{
14430 ImGuiContext& g = *GImGui;
14431 ImGuiWindow* window = g.NavWindow;
14433 if (window == NULL || g.NavWindowingTarget != NULL || (window->Flags & ImGuiWindowFlags_NoNavInputs))
14434 return;
14435
14437 if (!tab_pressed)
14438 return;
14439
14440 // Initiate tabbing request
14441 // (this is ALWAYS ENABLED, regardless of ImGuiConfigFlags_NavEnableKeyboard flag!)
14442 // See NavProcessItemForTabbingRequest() for a description of the various forward/backward tabbing cases with and without wrapping.
14443 const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
14444 if (nav_keyboard_active)
14445 g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.NavCursorVisible == false && g.ActiveId == 0) ? 0 : +1;
14446 else
14447 g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1;
14450 ImGuiDir clip_dir = (g.NavTabbingDir < 0) ? ImGuiDir_Up : ImGuiDir_Down;
14451 NavMoveRequestSubmit(ImGuiDir_None, clip_dir, move_flags, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable.
14452 g.NavTabbingCounter = -1;
14453}
14454
14455// Apply result from previous frame navigation directional move request. Always called from NavUpdate()
14457{
14458 ImGuiContext& g = *GImGui;
14459#if IMGUI_DEBUG_NAV_SCORING
14460 if (g.NavMoveFlags & ImGuiNavMoveFlags_DebugNoResult) // [DEBUG] Scoring all items in NavWindow at all times
14461 return;
14462#endif
14463
14464 // Select which result to use
14466
14467 // Tabbing forward wrap
14468 if ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && result == NULL)
14469 if ((g.NavTabbingCounter == 1 || g.NavTabbingDir == 0) && g.NavTabbingResultFirst.ID)
14470 result = &g.NavTabbingResultFirst;
14471
14472 // In a situation when there are no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result)
14474 if (result == NULL)
14475 {
14480 NavClearPreferredPosForAxis(axis); // On a failed move, clear preferred pos for this axis.
14481 IMGUI_DEBUG_LOG_NAV("[nav] NavMoveSubmitted but not led to a result!\n");
14482 return;
14483 }
14484
14485 // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
14488 result = &g.NavMoveResultLocalVisible;
14489
14490 // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules.
14493 result = &g.NavMoveResultOther;
14494 IM_ASSERT(g.NavWindow && result->Window);
14495
14496 // Scroll to keep newly navigated item fully into view.
14498 {
14499 ImRect rect_abs = WindowRectRelToAbs(result->Window, result->RectRel);
14500 ScrollToRectEx(result->Window, rect_abs, g.NavMoveScrollFlags);
14501
14503 {
14504 // FIXME: Should remove this? Or make more precise: use ScrollToRectEx() with edge?
14505 float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;
14506 SetScrollY(result->Window, scroll_target);
14507 }
14508 }
14509
14510 if (g.NavWindow != result->Window)
14511 {
14512 IMGUI_DEBUG_LOG_FOCUS("[focus] NavMoveRequest: SetNavWindow(\"%s\")\n", result->Window->Name);
14513 g.NavWindow = result->Window;
14515 }
14516
14517 // Clear active id unless requested not to
14518 // FIXME: ImGuiNavMoveFlags_NoClearActiveId is currently unused as we don't have a clear strategy to preserve active id after interaction,
14519 // so this is mostly provided as a gateway for further experiments (see #1418, #2890)
14520 if (g.ActiveId != result->ID && (g.NavMoveFlags & ImGuiNavMoveFlags_NoClearActiveId) == 0)
14521 ClearActiveID();
14522
14523 // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)
14524 // PageUp/PageDown however sets always set NavJustMovedTo (vs Home/End which doesn't) mimicking Windows behavior.
14526 {
14528 g.NavJustMovedToId = result->ID;
14533 //IMGUI_DEBUG_LOG_NAV("[nav] NavJustMovedFromFocusScopeId = 0x%08X, NavJustMovedToFocusScopeId = 0x%08X\n", g.NavJustMovedFromFocusScopeId, g.NavJustMovedToFocusScopeId);
14534 }
14535
14536 // Apply new NavID/Focus
14537 IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
14538 ImVec2 preferred_scoring_pos_rel = g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer];
14539 SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
14542
14543 // Restore last preferred position for current axis
14544 // (storing in RootWindowForNav-> as the info is desirable at the beginning of a Move Request. In theory all storage should use RootWindowForNav..)
14546 {
14547 preferred_scoring_pos_rel[axis] = result->RectRel.GetCenter()[axis];
14548 g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer] = preferred_scoring_pos_rel;
14549 }
14550
14551 // Tabbing: Activates Inputable, otherwise only Focus
14553 g.NavMoveFlags &= ~ImGuiNavMoveFlags_Activate;
14554
14555 // Activate
14557 {
14558 g.NavNextActivateId = result->ID;
14562 }
14563
14564 // Make nav cursor visible
14567}
14568
14569// Process Escape/NavCancel input (to close a popup, get back to parent, clear focus)
14570// FIXME: In order to support e.g. Escape to clear a selection we'll need:
14571// - either to store the equivalent of ActiveIdUsingKeyInputMask for a FocusScope and test for it.
14572// - either to move most/all of those tests to the epilogue/end functions of the scope they are dealing with (e.g. exit child window in EndChild()) or in EndFrame(), to allow an earlier intercept
14574{
14575 ImGuiContext& g = *GImGui;
14576 const bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
14577 const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
14578 if (!(nav_keyboard_active && IsKeyPressed(ImGuiKey_Escape, 0, ImGuiKeyOwner_NoOwner)) && !(nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadCancel, 0, ImGuiKeyOwner_NoOwner)))
14579 return;
14580
14581 IMGUI_DEBUG_LOG_NAV("[nav] NavUpdateCancelRequest()\n");
14582 if (g.ActiveId != 0)
14583 {
14584 ClearActiveID();
14585 }
14586 else if (g.NavLayer != ImGuiNavLayer_Main)
14587 {
14588 // Leave the "menu" layer
14591 }
14593 {
14594 // Exit child window
14595 ImGuiWindow* child_window = g.NavWindow->RootWindowForNav;
14596 ImGuiWindow* parent_window = child_window->ParentWindow;
14597 IM_ASSERT(child_window->ChildId != 0);
14598 FocusWindow(parent_window);
14599 SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_window->Rect()));
14601 }
14603 {
14604 // Close open popup/menu
14606 }
14607 else
14608 {
14609 // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
14610 // FIXME-NAV: This should happen on window appearing.
14612 if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup)))// || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
14613 g.NavWindow->NavLastIds[0] = 0;
14614
14615 // Clear nav focus
14617 g.NavId = 0;
14619 FocusWindow(NULL);
14620 }
14621}
14622
14623// Handle PageUp/PageDown/Home/End keys
14624// Called from NavUpdateCreateMoveRequest() which will use our output to create a move request
14625// FIXME-NAV: This doesn't work properly with NavFlattened siblings as we use NavWindow rectangle for reference
14626// FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid?
14628{
14629 ImGuiContext& g = *GImGui;
14630 ImGuiWindow* window = g.NavWindow;
14631 if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL)
14632 return 0.0f;
14633
14634 const bool page_up_held = IsKeyDown(ImGuiKey_PageUp, ImGuiKeyOwner_NoOwner);
14635 const bool page_down_held = IsKeyDown(ImGuiKey_PageDown, ImGuiKeyOwner_NoOwner);
14638 if (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out
14639 return 0.0f;
14640
14643
14644 if ((window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Main)) == 0 && window->DC.NavWindowHasScrollY)
14645 {
14646 // Fallback manual-scroll when window has no navigable item
14648 SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
14650 SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
14651 else if (home_pressed)
14652 SetScrollY(window, 0.0f);
14653 else if (end_pressed)
14654 SetScrollY(window, window->ScrollMax.y);
14655 }
14656 else
14657 {
14658 ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
14659 const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->FontRefSize * 1.0f + nav_rect_rel.GetHeight());
14660 float nav_scoring_rect_offset_y = 0.0f;
14661 if (IsKeyPressed(ImGuiKey_PageUp, true))
14662 {
14663 nav_scoring_rect_offset_y = -page_offset_y;
14664 g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item)
14667 }
14668 else if (IsKeyPressed(ImGuiKey_PageDown, true))
14669 {
14670 nav_scoring_rect_offset_y = +page_offset_y;
14671 g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)
14674 }
14675 else if (home_pressed)
14676 {
14677 // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
14678 // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdgeY flag, we don't scroll immediately to avoid scrolling happening before nav result.
14679 // Preserve current horizontal position if we have any.
14680 nav_rect_rel.Min.y = nav_rect_rel.Max.y = 0.0f;
14681 if (nav_rect_rel.IsInverted())
14682 nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
14685 // FIXME-NAV: MoveClipDir left to _None, intentional?
14686 }
14687 else if (end_pressed)
14688 {
14689 nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ContentSize.y;
14690 if (nav_rect_rel.IsInverted())
14691 nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
14694 // FIXME-NAV: MoveClipDir left to _None, intentional?
14695 }
14696 return nav_scoring_rect_offset_y;
14697 }
14698 return 0.0f;
14699}
14700
14702{
14703 ImGuiContext& g = *GImGui;
14704
14705 // Show CTRL+TAB list window
14706 if (g.NavWindowingTarget != NULL)
14708
14709 // Perform wrap-around in menus
14710 // FIXME-NAV: Wrap may need to apply a weight bias on the other axis. e.g. 4x4 grid with 2 last items missing on last item won't handle LoopY/WrapY correctly.
14711 // FIXME-NAV: Wrap (not Loop) support could be handled by the scoring function and then WrapX would function without an extra frame.
14714}
14715
14717{
14718 ImGuiContext& g = *GImGui;
14719 ImGuiWindow* window = g.NavWindow;
14720
14721 bool do_forward = false;
14722 ImRect bb_rel = window->NavRectRel[g.NavLayer];
14723 ImGuiDir clip_dir = g.NavMoveDir;
14724
14725 const ImGuiNavMoveFlags move_flags = g.NavMoveFlags;
14726 //const ImGuiAxis move_axis = (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X;
14728 {
14729 bb_rel.Min.x = bb_rel.Max.x = window->ContentSize.x + window->WindowPadding.x;
14730 if (move_flags & ImGuiNavMoveFlags_WrapX)
14731 {
14732 bb_rel.TranslateY(-bb_rel.GetHeight()); // Previous row
14733 clip_dir = ImGuiDir_Up;
14734 }
14735 do_forward = true;
14736 }
14738 {
14739 bb_rel.Min.x = bb_rel.Max.x = -window->WindowPadding.x;
14740 if (move_flags & ImGuiNavMoveFlags_WrapX)
14741 {
14742 bb_rel.TranslateY(+bb_rel.GetHeight()); // Next row
14743 clip_dir = ImGuiDir_Down;
14744 }
14745 do_forward = true;
14746 }
14748 {
14749 bb_rel.Min.y = bb_rel.Max.y = window->ContentSize.y + window->WindowPadding.y;
14750 if (move_flags & ImGuiNavMoveFlags_WrapY)
14751 {
14752 bb_rel.TranslateX(-bb_rel.GetWidth()); // Previous column
14753 clip_dir = ImGuiDir_Left;
14754 }
14755 do_forward = true;
14756 }
14758 {
14759 bb_rel.Min.y = bb_rel.Max.y = -window->WindowPadding.y;
14760 if (move_flags & ImGuiNavMoveFlags_WrapY)
14761 {
14762 bb_rel.TranslateX(+bb_rel.GetWidth()); // Next column
14763 clip_dir = ImGuiDir_Right;
14764 }
14765 do_forward = true;
14766 }
14767 if (!do_forward)
14768 return;
14769 window->NavRectRel[g.NavLayer] = bb_rel;
14772 NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags);
14773}
14774
14775// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext)
14776// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically.
14777// If you want a window to never be focused, you may use the e.g. NoInputs flag.
14779{
14780 return window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus);
14781}
14782
14783static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
14784{
14785 ImGuiContext& g = *GImGui;
14786 for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir)
14788 return g.WindowsFocusOrder[i];
14789 return NULL;
14790}
14791
14792static void NavUpdateWindowingTarget(int focus_change_dir)
14793{
14794 ImGuiContext& g = *GImGui;
14797 return;
14798
14799 const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget);
14800 ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
14801 if (!window_target)
14802 window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir);
14803 if (window_target) // Don't reset windowing target if there's a single window in the list
14804 {
14805 g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target;
14807 }
14808 g.NavWindowingToggleLayer = false;
14809}
14810
14811// Apply focus and close overlay
14812static void ImGui::NavUpdateWindowingApplyFocus(ImGuiWindow* apply_focus_window)
14813{
14814 // FIXME: Many actions here could be part of a higher-level/reused function. Why aren't they in FocusWindow() ?
14815 // Investigate for each of them: ClearActiveID(), NavRestoreHighlightAfterMove(), NavRestoreLastChildNavWindow(), ClosePopupsOverWindow(), NavInitWindow()
14816 ImGuiContext& g = *GImGui;
14817 if (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow)
14818 {
14819 ImGuiViewport* previous_viewport = g.NavWindow ? g.NavWindow->Viewport : NULL;
14820 ClearActiveID();
14822 ClosePopupsOverWindow(apply_focus_window, false);
14824 apply_focus_window = g.NavWindow;
14825 if (apply_focus_window->NavLastIds[0] == 0)
14826 NavInitWindow(apply_focus_window, false);
14827
14828 // If the window has ONLY a menu layer (no main layer), select it directly
14829 // Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame,
14830 // so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since
14831 // the target window as already been previewed once.
14832 // FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases,
14833 // we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask*
14834 // won't be valid.
14835 if (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu))
14837
14838 // Request OS level focus
14839 if (apply_focus_window->Viewport != previous_viewport && g.PlatformIO.Platform_SetWindowFocus)
14840 g.PlatformIO.Platform_SetWindowFocus(apply_focus_window->Viewport);
14841 }
14842 g.NavWindowingTarget = NULL;
14843}
14844
14845// Windowing management mode
14846// Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer)
14847// Gamepad: Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer)
14849{
14850 ImGuiContext& g = *GImGui;
14851 ImGuiIO& io = g.IO;
14852
14853 ImGuiWindow* apply_focus_window = NULL;
14854 bool apply_toggle_layer = false;
14855
14856 ImGuiWindow* modal_window = GetTopMostPopupModal();
14857 bool allow_windowing = (modal_window == NULL); // FIXME: This prevent CTRL+TAB from being usable with windows that are inside the Begin-stack of that modal.
14858 if (!allow_windowing)
14859 g.NavWindowingTarget = NULL;
14860
14861 // Fade out
14862 if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)
14863 {
14865 if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
14866 g.NavWindowingTargetAnim = NULL;
14867 }
14868
14869 // Start CTRL+Tab or Square+L/R window selection
14870 // (g.ConfigNavWindowingKeyNext/g.ConfigNavWindowingKeyPrev defaults are ImGuiMod_Ctrl|ImGuiKey_Tab and ImGuiMod_Ctrl|ImGuiMod_Shift|ImGuiKey_Tab)
14871 const ImGuiID owner_id = ImHashStr("##NavUpdateWindowing");
14872 const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
14873 const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
14874 const bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways, owner_id);
14875 const bool keyboard_prev_window = allow_windowing && g.ConfigNavWindowingKeyPrev && Shortcut(g.ConfigNavWindowingKeyPrev, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways, owner_id);
14876 const bool start_windowing_with_gamepad = allow_windowing && nav_gamepad_active && !g.NavWindowingTarget && Shortcut(ImGuiKey_NavGamepadMenu, ImGuiInputFlags_RouteAlways, owner_id);
14877 const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && (keyboard_next_window || keyboard_prev_window); // Note: enabled even without NavEnableKeyboard!
14878 bool just_started_windowing_from_null_focus = false;
14879 if (start_windowing_with_gamepad || start_windowing_with_keyboard)
14880 if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
14881 {
14882 if (start_windowing_with_keyboard || g.ConfigNavWindowingWithGamepad)
14883 g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // Current location
14886 g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer
14888 if (g.NavWindow == NULL)
14889 just_started_windowing_from_null_focus = true;
14890
14891 // Manually register ownership of our mods. Using a global route in the Shortcut() calls instead would probably be correct but may have more side-effects.
14892 if (keyboard_next_window || keyboard_prev_window)
14894 }
14895
14896 // Gamepad update
14898 {
14899 if (g.NavWindowingTarget != NULL)
14900 {
14901 // Highlight only appears after a brief time holding the button, so that a fast tap on ImGuiKey_NavGamepadMenu (to toggle NavLayer) doesn't add visual noise
14902 // However inputs are accepted immediately, so you press ImGuiKey_NavGamepadMenu + L1/R1 fast.
14905
14906 // Select window to focus
14907 const int focus_change_dir = (int)IsKeyPressed(ImGuiKey_GamepadL1) - (int)IsKeyPressed(ImGuiKey_GamepadR1);
14908 if (focus_change_dir != 0 && !just_started_windowing_from_null_focus)
14909 {
14910 NavUpdateWindowingTarget(focus_change_dir);
14912 }
14913 }
14914
14915 // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most)
14917 {
14918 g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
14920 apply_toggle_layer = true;
14921 else if (!g.NavWindowingToggleLayer)
14922 apply_focus_window = g.NavWindowingTarget;
14923 g.NavWindowingTarget = NULL;
14924 g.NavWindowingToggleLayer = false;
14925 }
14926 }
14927
14928 // Keyboard: Focus
14930 {
14931 // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
14933 IM_ASSERT(shared_mods != 0); // Next/Prev shortcut currently needs a shared modifier to "hold", otherwise Prev actions would keep cycling between two windows.
14936 if ((keyboard_next_window || keyboard_prev_window) && !just_started_windowing_from_null_focus)
14937 NavUpdateWindowingTarget(keyboard_next_window ? -1 : +1);
14938 else if ((io.KeyMods & shared_mods) != shared_mods)
14939 apply_focus_window = g.NavWindowingTarget;
14940 }
14941
14942 // Keyboard: Press and Release ALT to toggle menu layer
14943 const ImGuiKey windowing_toggle_keys[] = { ImGuiKey_LeftAlt, ImGuiKey_RightAlt };
14944 bool windowing_toggle_layer_start = false;
14945 if (g.NavWindow != NULL && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
14946 for (ImGuiKey windowing_toggle_key : windowing_toggle_keys)
14947 if (nav_keyboard_active && IsKeyPressed(windowing_toggle_key, 0, ImGuiKeyOwner_NoOwner))
14948 {
14949 windowing_toggle_layer_start = true;
14950 g.NavWindowingToggleLayer = true;
14951 g.NavWindowingToggleKey = windowing_toggle_key;
14953 break;
14954 }
14956 {
14957 // We cancel toggling nav layer when any text has been typed (generally while holding Alt). (See #370)
14958 // We cancel toggling nav layer when other modifiers are pressed. (See #4439)
14959 // - AltGR is Alt+Ctrl on some layout but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl).
14960 // We cancel toggling nav layer if an owner has claimed the key.
14961 if (io.InputQueueCharacters.Size > 0 || io.KeyCtrl || io.KeyShift || io.KeySuper)
14962 g.NavWindowingToggleLayer = false;
14963 else if (windowing_toggle_layer_start == false && g.LastKeyboardKeyPressTime == g.Time)
14964 g.NavWindowingToggleLayer = false;
14966 g.NavWindowingToggleLayer = false;
14967
14968 // Apply layer toggle on Alt release
14969 // Important: as before version <18314 we lacked an explicit IO event for focus gain/loss, we also compare mouse validity to detect old backends clearing mouse pos on focus loss.
14971 if (g.ActiveId == 0 || g.ActiveIdAllowOverlap)
14973 apply_toggle_layer = true;
14975 g.NavWindowingToggleLayer = false;
14976 }
14977
14978 // Move window
14980 {
14981 ImVec2 nav_move_dir;
14986 if (nav_move_dir.x != 0.0f || nav_move_dir.y != 0.0f)
14987 {
14988 const float NAV_MOVE_SPEED = 800.0f;
14989 const float move_step = NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
14990 g.NavWindowingAccumDeltaPos += nav_move_dir * move_step;
14991 g.NavHighlightItemUnderNav = true;
14992 ImVec2 accum_floored = ImTrunc(g.NavWindowingAccumDeltaPos);
14993 if (accum_floored.x != 0.0f || accum_floored.y != 0.0f)
14994 {
14996 SetWindowPos(moving_window, moving_window->Pos + accum_floored, ImGuiCond_Always);
14997 g.NavWindowingAccumDeltaPos -= accum_floored;
14998 }
14999 }
15000 }
15001
15002 // Apply final focus
15003 if (apply_focus_window)
15004 NavUpdateWindowingApplyFocus(apply_focus_window);
15005
15006 // Apply menu/layer toggle
15007 if (apply_toggle_layer && g.NavWindow)
15008 {
15009 ClearActiveID();
15010
15011 // Move to parent menu if necessary
15012 ImGuiWindow* new_nav_window = g.NavWindow;
15013 while (new_nav_window->ParentWindow
15014 && (new_nav_window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
15015 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
15016 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
15017 new_nav_window = new_nav_window->ParentWindow;
15018 if (new_nav_window != g.NavWindow)
15019 {
15020 ImGuiWindow* old_nav_window = g.NavWindow;
15021 FocusWindow(new_nav_window);
15022 new_nav_window->NavLastChildNavWindow = old_nav_window;
15023 }
15024
15025 // Toggle layer
15026 const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
15027 if (new_nav_layer != g.NavLayer)
15028 {
15029 // Reinitialize navigation when entering menu bar with the Alt key (FIXME: could be a properly of the layer?)
15030 const bool preserve_layer_1_nav_id = (new_nav_window->DockNodeAsHost != NULL);
15031 if (new_nav_layer == ImGuiNavLayer_Menu && !preserve_layer_1_nav_id)
15032 g.NavWindow->NavLastIds[new_nav_layer] = 0;
15033 NavRestoreLayer(new_nav_layer);
15035 }
15036 }
15037}
15038
15039// Window has already passed the IsWindowNavFocusable()
15041{
15042 if (window->Flags & ImGuiWindowFlags_Popup)
15044 if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0)
15046 if (window->DockNodeAsHost)
15047 return "(Dock node)"; // Not normally shown to user.
15049}
15050
15051// Overlay displayed when using CTRL+TAB. Called by EndFrame().
15053{
15054 ImGuiContext& g = *GImGui;
15055 IM_ASSERT(g.NavWindowingTarget != NULL);
15056
15058 return;
15059
15060 if (g.NavWindowingListWindow == NULL)
15061 g.NavWindowingListWindow = FindWindowByName("##NavWindowingOverlay");
15062 const ImGuiViewport* viewport = /*g.NavWindow ? g.NavWindow->Viewport :*/ GetMainViewport();
15063 SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX));
15064 SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
15067 if (g.ContextName[0] != 0)
15069 for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
15070 {
15071 ImGuiWindow* window = g.WindowsFocusOrder[n];
15072 IM_ASSERT(window != NULL); // Fix static analyzers
15073 if (!IsWindowNavFocusable(window))
15074 continue;
15075 const char* label = window->Name;
15076 if (label == FindRenderedTextEnd(label))
15078 Selectable(label, g.NavWindowingTarget == window);
15079 }
15080 End();
15081 PopStyleVar();
15082}
15083
15084//-----------------------------------------------------------------------------
15085// [SECTION] DRAG AND DROP
15086//-----------------------------------------------------------------------------
15087
15089{
15090 ImGuiContext& g = *GImGui;
15091 return g.DragDropActive;
15092}
15093
15095{
15096 ImGuiContext& g = *GImGui;
15097 if (g.DragDropActive)
15098 IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] ClearDragDrop()\n");
15099 g.DragDropActive = false;
15105
15107 memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
15108}
15109
15111{
15112 ImGuiContext& g = *GImGui;
15115 return ret;
15116}
15117
15118// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource()
15119// If the item has an identifier:
15120// - This assume/require the item to be activated (typically via ButtonBehavior).
15121// - Therefore if you want to use this with a mouse button other than left mouse button, it is up to the item itself to activate with another button.
15122// - We then pull and use the mouse button that was used to activate the item and use it to carry on the drag.
15123// If the item has no identifier:
15124// - Currently always assume left mouse button.
15126{
15127 ImGuiContext& g = *GImGui;
15128 ImGuiWindow* window = g.CurrentWindow;
15129
15130 // FIXME-DRAGDROP: While in the common-most "drag from non-zero active id" case we can tell the mouse button,
15131 // in both SourceExtern and id==0 cases we may requires something else (explicit flags or some heuristic).
15133
15134 bool source_drag_active = false;
15135 ImGuiID source_id = 0;
15136 ImGuiID source_parent_id = 0;
15137 if ((flags & ImGuiDragDropFlags_SourceExtern) == 0)
15138 {
15139 source_id = g.LastItemData.ID;
15140 if (source_id != 0)
15141 {
15142 // Common path: items with ID
15143 if (g.ActiveId != source_id)
15144 return false;
15145 if (g.ActiveIdMouseButton != -1)
15146 mouse_button = g.ActiveIdMouseButton;
15147 if (g.IO.MouseDown[mouse_button] == false || window->SkipItems)
15148 return false;
15149 g.ActiveIdAllowOverlap = false;
15150 }
15151 else
15152 {
15153 // Uncommon path: items without ID
15154 if (g.IO.MouseDown[mouse_button] == false || window->SkipItems)
15155 return false;
15156 if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
15157 return false;
15158
15159 // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
15160 // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag.
15162 {
15163 IM_ASSERT(0);
15164 return false;
15165 }
15166
15167 // Magic fallback to handle items with no assigned ID, e.g. Text(), Image()
15168 // We build a throwaway ID based on current ID stack + relative AABB of items in window.
15169 // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
15170 // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
15171 // Rely on keeping other window->LastItemXXX fields intact.
15172 source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect);
15173 KeepAliveID(source_id);
15174 bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id, g.LastItemData.ItemFlags);
15175 if (is_hovered && g.IO.MouseClicked[mouse_button])
15176 {
15177 SetActiveID(source_id, window);
15178 FocusWindow(window);
15179 }
15180 if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker.
15181 g.ActiveIdAllowOverlap = is_hovered;
15182 }
15183 if (g.ActiveId != source_id)
15184 return false;
15185 source_parent_id = window->IDStack.back();
15186 source_drag_active = IsMouseDragging(mouse_button);
15187
15188 // Disable navigation and key inputs while dragging + cancel existing request if any
15190 }
15191 else
15192 {
15193 // When ImGuiDragDropFlags_SourceExtern is set:
15194 window = NULL;
15195 source_id = ImHashStr("#SourceExtern");
15196 source_drag_active = true;
15197 mouse_button = g.IO.MouseDown[0] ? 0 : -1;
15198 KeepAliveID(source_id);
15199 SetActiveID(source_id, NULL);
15200 }
15201
15202 IM_ASSERT(g.DragDropWithinTarget == false); // Can't nest BeginDragDropSource() and BeginDragDropTarget()
15203 if (!source_drag_active)
15204 return false;
15205
15206 // Activate drag and drop
15207 if (!g.DragDropActive)
15208 {
15209 IM_ASSERT(source_id != 0);
15210 ClearDragDrop();
15211 IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] BeginDragDropSource() DragDropActive = true, source_id = 0x%08X%s\n",
15212 source_id, (flags & ImGuiDragDropFlags_SourceExtern) ? " (EXTERN)" : "");
15213 ImGuiPayload& payload = g.DragDropPayload;
15214 payload.SourceId = source_id;
15215 payload.SourceParentId = source_parent_id;
15216 g.DragDropActive = true;
15217 g.DragDropSourceFlags = flags;
15218 g.DragDropMouseButton = mouse_button;
15219 if (payload.SourceId == g.ActiveId)
15221 }
15223 g.DragDropWithinSource = true;
15224
15226 {
15227 // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
15228 // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
15229 bool ret;
15231 ret = BeginTooltipHidden();
15232 else
15233 ret = BeginTooltip();
15234 IM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin("##Hidden", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame().
15235 IM_UNUSED(ret);
15236 }
15237
15239 g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
15240
15241 return true;
15242}
15243
15245{
15246 ImGuiContext& g = *GImGui;
15248 IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?");
15249
15251 EndTooltip();
15252
15253 // Discard the drag if have not called SetDragDropPayload()
15254 if (g.DragDropPayload.DataFrameCount == -1)
15255 ClearDragDrop();
15256 g.DragDropWithinSource = false;
15257}
15258
15259// Use 'cond' to choose to submit payload on drag start or every frame
15260bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)
15261{
15262 ImGuiContext& g = *GImGui;
15263 ImGuiPayload& payload = g.DragDropPayload;
15264 if (cond == 0)
15265 cond = ImGuiCond_Always;
15266
15267 IM_ASSERT(type != NULL);
15268 IM_ASSERT(ImStrlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
15269 IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
15270 IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
15271 IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource()
15272
15273 if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
15274 {
15275 // Copy payload
15276 ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
15278 if (data_size > sizeof(g.DragDropPayloadBufLocal))
15279 {
15280 // Store in heap
15281 g.DragDropPayloadBufHeap.resize((int)data_size);
15282 payload.Data = g.DragDropPayloadBufHeap.Data;
15283 memcpy(payload.Data, data, data_size);
15284 }
15285 else if (data_size > 0)
15286 {
15287 // Store locally
15288 memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
15289 payload.Data = g.DragDropPayloadBufLocal;
15290 memcpy(payload.Data, data, data_size);
15291 }
15292 else
15293 {
15294 payload.Data = NULL;
15295 }
15296 payload.DataSize = (int)data_size;
15297 }
15298 payload.DataFrameCount = g.FrameCount;
15299
15300 // Return whether the payload has been accepted
15302}
15303
15305{
15306 ImGuiContext& g = *GImGui;
15307 if (!g.DragDropActive)
15308 return false;
15309
15310 ImGuiWindow* window = g.CurrentWindow;
15311 ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
15312 if (hovered_window == NULL || window->RootWindowDockTree != hovered_window->RootWindowDockTree)
15313 return false;
15314 IM_ASSERT(id != 0);
15315 if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
15316 return false;
15317 if (window->SkipItems)
15318 return false;
15319
15320 IM_ASSERT(g.DragDropWithinTarget == false && g.DragDropWithinSource == false); // Can't nest BeginDragDropSource() and BeginDragDropTarget()
15321 g.DragDropTargetRect = bb;
15322 g.DragDropTargetClipRect = window->ClipRect; // May want to be overridden by user depending on use case?
15323 g.DragDropTargetId = id;
15324 g.DragDropWithinTarget = true;
15325 return true;
15326}
15327
15328// We don't use BeginDragDropTargetCustom() and duplicate its code because:
15329// 1) we use LastItemData's ImGuiItemStatusFlags_HoveredRect which handles items that push a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them.
15330// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can.
15331// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case)
15333{
15334 ImGuiContext& g = *GImGui;
15335 if (!g.DragDropActive)
15336 return false;
15337
15338 ImGuiWindow* window = g.CurrentWindow;
15340 return false;
15341 ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
15342 if (hovered_window == NULL || window->RootWindowDockTree != hovered_window->RootWindowDockTree || window->SkipItems)
15343 return false;
15344
15346 ImGuiID id = g.LastItemData.ID;
15347 if (id == 0)
15348 {
15349 id = window->GetIDFromRectangle(display_rect);
15350 KeepAliveID(id);
15351 }
15352 if (g.DragDropPayload.SourceId == id)
15353 return false;
15354
15355 IM_ASSERT(g.DragDropWithinTarget == false && g.DragDropWithinSource == false); // Can't nest BeginDragDropSource() and BeginDragDropTarget()
15356 g.DragDropTargetRect = display_rect;
15358 g.DragDropTargetId = id;
15359 g.DragDropWithinTarget = true;
15360 return true;
15361}
15362
15364{
15365 ImGuiContext& g = *GImGui;
15366 return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
15367}
15368
15370{
15371 ImGuiContext& g = *GImGui;
15372 ImGuiPayload& payload = g.DragDropPayload;
15373 IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
15374 IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ?
15375 if (type != NULL && !payload.IsDataType(type))
15376 return NULL;
15377
15378 // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
15379 // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
15380 const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
15382 float r_surface = r.GetWidth() * r.GetHeight();
15383 if (r_surface > g.DragDropAcceptIdCurrRectSurface)
15384 return NULL;
15385
15386 g.DragDropAcceptFlags = flags;
15388 g.DragDropAcceptIdCurrRectSurface = r_surface;
15389 //IMGUI_DEBUG_LOG("AcceptDragDropPayload(): %08X: accept\n", g.DragDropTargetId);
15390
15391 // Render default drop visuals
15392 payload.Preview = was_accepted_previously;
15393 flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that live for 1 frame)
15394 if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
15396
15399 payload.Delivery = was_accepted_previously && (g.DragDropSourceFrameCount < g.FrameCount);
15400 else
15401 payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting OS window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased()
15402 if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
15403 return NULL;
15404
15405 if (payload.Delivery)
15406 IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] AcceptDragDropPayload(): 0x%08X: payload delivery\n", g.DragDropTargetId);
15407 return &payload;
15408}
15409
15410// FIXME-STYLE FIXME-DRAGDROP: Settle on a proper default visuals for drop target.
15411void ImGui::RenderDragDropTargetRect(const ImRect& bb, const ImRect& item_clip_rect)
15412{
15413 ImGuiContext& g = *GImGui;
15414 ImGuiWindow* window = g.CurrentWindow;
15415 ImRect bb_display = bb;
15416 bb_display.ClipWith(item_clip_rect); // Clip THEN expand so we have a way to visualize that target is not entirely visible.
15417 bb_display.Expand(3.5f);
15418 bool push_clip_rect = !window->ClipRect.Contains(bb_display);
15419 if (push_clip_rect)
15421 window->DrawList->AddRect(bb_display.Min, bb_display.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f); // FIXME-DPI
15422 if (push_clip_rect)
15423 window->DrawList->PopClipRect();
15424}
15425
15427{
15428 ImGuiContext& g = *GImGui;
15429 return (g.DragDropActive && g.DragDropPayload.DataFrameCount != -1) ? &g.DragDropPayload : NULL;
15430}
15431
15433{
15434 ImGuiContext& g = *GImGui;
15437 g.DragDropWithinTarget = false;
15438
15439 // Clear drag and drop state payload right after delivery
15441 ClearDragDrop();
15442}
15443
15444//-----------------------------------------------------------------------------
15445// [SECTION] LOGGING/CAPTURING
15446//-----------------------------------------------------------------------------
15447// All text output from the interface can be captured into tty/file/clipboard.
15448// By default, tree nodes are automatically opened during logging.
15449//-----------------------------------------------------------------------------
15450
15451// Pass text data straight to log (without being displayed)
15452static inline void LogTextV(ImGuiContext& g, const char* fmt, va_list args)
15453{
15454 if (g.LogFile)
15455 {
15456 g.LogBuffer.Buf.resize(0);
15457 g.LogBuffer.appendfv(fmt, args);
15458 ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile);
15459 }
15460 else
15461 {
15462 g.LogBuffer.appendfv(fmt, args);
15463 }
15464}
15465
15466void ImGui::LogText(const char* fmt, ...)
15467{
15468 ImGuiContext& g = *GImGui;
15469 if (!g.LogEnabled)
15470 return;
15471
15472 va_list args;
15473 va_start(args, fmt);
15474 LogTextV(g, fmt, args);
15475 va_end(args);
15476}
15477
15478void ImGui::LogTextV(const char* fmt, va_list args)
15479{
15480 ImGuiContext& g = *GImGui;
15481 if (!g.LogEnabled)
15482 return;
15483
15484 LogTextV(g, fmt, args);
15485}
15486
15487// Internal version that takes a position to decide on newline placement and pad items according to their depth.
15488// We split text into individual lines to add current tree level padding
15489// FIXME: This code is a little complicated perhaps, considering simplifying the whole system.
15490void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end)
15491{
15492 ImGuiContext& g = *GImGui;
15493 ImGuiWindow* window = g.CurrentWindow;
15494
15495 const char* prefix = g.LogNextPrefix;
15496 const char* suffix = g.LogNextSuffix;
15497 g.LogNextPrefix = g.LogNextSuffix = NULL;
15498
15499 if (!text_end)
15500 text_end = FindRenderedTextEnd(text, text_end);
15501
15502 const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1);
15503 if (ref_pos)
15504 g.LogLinePosY = ref_pos->y;
15505 if (log_new_line)
15506 {
15508 g.LogLineFirstItem = true;
15509 }
15510
15511 if (prefix)
15512 LogRenderedText(ref_pos, prefix, prefix + ImStrlen(prefix)); // Calculate end ourself to ensure "##" are included here.
15513
15514 // Re-adjust padding if we have popped out of our starting depth
15515 if (g.LogDepthRef > window->DC.TreeDepth)
15516 g.LogDepthRef = window->DC.TreeDepth;
15517 const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef);
15518
15519 const char* text_remaining = text;
15520 for (;;)
15521 {
15522 // Split the string. Each new line (after a '\n') is followed by indentation corresponding to the current depth of our log entry.
15523 // We don't add a trailing \n yet to allow a subsequent item on the same line to be captured.
15524 const char* line_start = text_remaining;
15525 const char* line_end = ImStreolRange(line_start, text_end);
15526 const bool is_last_line = (line_end == text_end);
15527 if (line_start != line_end || !is_last_line)
15528 {
15529 const int line_length = (int)(line_end - line_start);
15530 const int indentation = g.LogLineFirstItem ? tree_depth * 4 : 1;
15531 LogText("%*s%.*s", indentation, "", line_length, line_start);
15532 g.LogLineFirstItem = false;
15533 if (*line_end == '\n')
15534 {
15536 g.LogLineFirstItem = true;
15537 }
15538 }
15539 if (is_last_line)
15540 break;
15541 text_remaining = line_end + 1;
15542 }
15543
15544 if (suffix)
15545 LogRenderedText(ref_pos, suffix, suffix + ImStrlen(suffix));
15546}
15547
15548// Start logging/capturing text output
15549void ImGui::LogBegin(ImGuiLogFlags flags, int auto_open_depth)
15550{
15551 ImGuiContext& g = *GImGui;
15552 ImGuiWindow* window = g.CurrentWindow;
15553 IM_ASSERT(g.LogEnabled == false);
15554 IM_ASSERT(g.LogFile == NULL && g.LogBuffer.empty());
15555 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiLogFlags_OutputMask_)); // Check that only 1 type flag is used
15556
15557 g.LogEnabled = g.ItemUnclipByLog = true;
15558 g.LogFlags = flags;
15559 g.LogWindow = window;
15560 g.LogNextPrefix = g.LogNextSuffix = NULL;
15561 g.LogDepthRef = window->DC.TreeDepth;
15562 g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault);
15563 g.LogLinePosY = FLT_MAX;
15564 g.LogLineFirstItem = true;
15565}
15566
15567// Important: doesn't copy underlying data, use carefully (prefix/suffix must be in scope at the time of the next LogRenderedText)
15568void ImGui::LogSetNextTextDecoration(const char* prefix, const char* suffix)
15569{
15570 ImGuiContext& g = *GImGui;
15571 g.LogNextPrefix = prefix;
15572 g.LogNextSuffix = suffix;
15573}
15574
15575void ImGui::LogToTTY(int auto_open_depth)
15576{
15577 ImGuiContext& g = *GImGui;
15578 if (g.LogEnabled)
15579 return;
15580 IM_UNUSED(auto_open_depth);
15581#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
15582 LogBegin(ImGuiLogFlags_OutputTTY, auto_open_depth);
15583 g.LogFile = stdout;
15584#endif
15585}
15586
15587// Start logging/capturing text output to given file
15588void ImGui::LogToFile(int auto_open_depth, const char* filename)
15589{
15590 ImGuiContext& g = *GImGui;
15591 if (g.LogEnabled)
15592 return;
15593
15594 // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still
15595 // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE.
15596 // By opening the file in binary mode "ab" we have consistent output everywhere.
15597 if (!filename)
15598 filename = g.IO.LogFilename;
15599 if (!filename || !filename[0])
15600 return;
15601 ImFileHandle f = ImFileOpen(filename, "ab");
15602 if (!f)
15603 {
15604 IM_ASSERT(0);
15605 return;
15606 }
15607
15608 LogBegin(ImGuiLogFlags_OutputFile, auto_open_depth);
15609 g.LogFile = f;
15610}
15611
15612// Start logging/capturing text output to clipboard
15613void ImGui::LogToClipboard(int auto_open_depth)
15614{
15615 ImGuiContext& g = *GImGui;
15616 if (g.LogEnabled)
15617 return;
15618 LogBegin(ImGuiLogFlags_OutputClipboard, auto_open_depth);
15619}
15620
15621void ImGui::LogToBuffer(int auto_open_depth)
15622{
15623 ImGuiContext& g = *GImGui;
15624 if (g.LogEnabled)
15625 return;
15626 LogBegin(ImGuiLogFlags_OutputBuffer, auto_open_depth);
15627}
15628
15630{
15631 ImGuiContext& g = *GImGui;
15632 if (!g.LogEnabled)
15633 return;
15634
15637 {
15639#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
15640 fflush(g.LogFile);
15641#endif
15642 break;
15645 break;
15647 break;
15649 if (!g.LogBuffer.empty())
15651 break;
15652 default:
15653 IM_ASSERT(0);
15654 break;
15655 }
15656
15657 g.LogEnabled = g.ItemUnclipByLog = false;
15659 g.LogFile = NULL;
15660 g.LogBuffer.clear();
15661}
15662
15663// Helper to display logging buttons
15664// FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!)
15666{
15667 ImGuiContext& g = *GImGui;
15668
15669 PushID("LogButtons");
15670#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
15671 const bool log_to_tty = Button("Log To TTY"); SameLine();
15672#else
15673 const bool log_to_tty = false;
15674#endif
15675 const bool log_to_file = Button("Log To File"); SameLine();
15676 const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
15678 SetNextItemWidth(80.0f);
15679 SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL);
15680 PopItemFlag();
15681 PopID();
15682
15683 // Start logging at the end of the function so that the buttons don't appear in the log
15684 if (log_to_tty)
15685 LogToTTY();
15686 if (log_to_file)
15687 LogToFile();
15688 if (log_to_clipboard)
15690}
15691
15692//-----------------------------------------------------------------------------
15693// [SECTION] SETTINGS
15694//-----------------------------------------------------------------------------
15695// - UpdateSettings() [Internal]
15696// - MarkIniSettingsDirty() [Internal]
15697// - FindSettingsHandler() [Internal]
15698// - ClearIniSettings() [Internal]
15699// - LoadIniSettingsFromDisk()
15700// - LoadIniSettingsFromMemory()
15701// - SaveIniSettingsToDisk()
15702// - SaveIniSettingsToMemory()
15703//-----------------------------------------------------------------------------
15704// - CreateNewWindowSettings() [Internal]
15705// - FindWindowSettingsByID() [Internal]
15706// - FindWindowSettingsByWindow() [Internal]
15707// - ClearWindowSettings() [Internal]
15708// - WindowSettingsHandler_***() [Internal]
15709//-----------------------------------------------------------------------------
15710
15711// Called by NewFrame()
15713{
15714 // Load settings on first frame (if not explicitly loaded manually before)
15715 ImGuiContext& g = *GImGui;
15716 if (!g.SettingsLoaded)
15717 {
15719 if (g.IO.IniFilename)
15721 g.SettingsLoaded = true;
15722 }
15723
15724 // Save settings (with a delay after the last modification, so we don't spam disk too much)
15725 if (g.SettingsDirtyTimer > 0.0f)
15726 {
15728 if (g.SettingsDirtyTimer <= 0.0f)
15729 {
15730 if (g.IO.IniFilename != NULL)
15732 else
15733 g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
15734 g.SettingsDirtyTimer = 0.0f;
15735 }
15736 }
15737}
15738
15740{
15741 ImGuiContext& g = *GImGui;
15742 if (g.SettingsDirtyTimer <= 0.0f)
15744}
15745
15747{
15748 ImGuiContext& g = *GImGui;
15749 if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
15750 if (g.SettingsDirtyTimer <= 0.0f)
15752}
15753
15755{
15756 ImGuiContext& g = *GImGui;
15757 IM_ASSERT(FindSettingsHandler(handler->TypeName) == NULL);
15758 g.SettingsHandlers.push_back(*handler);
15759}
15760
15761void ImGui::RemoveSettingsHandler(const char* type_name)
15762{
15763 ImGuiContext& g = *GImGui;
15764 if (ImGuiSettingsHandler* handler = FindSettingsHandler(type_name))
15765 g.SettingsHandlers.erase(handler);
15766}
15767
15769{
15770 ImGuiContext& g = *GImGui;
15771 const ImGuiID type_hash = ImHashStr(type_name);
15772 for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
15773 if (handler.TypeHash == type_hash)
15774 return &handler;
15775 return NULL;
15776}
15777
15778// Clear all settings (windows, tables, docking etc.)
15780{
15781 ImGuiContext& g = *GImGui;
15783 for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
15784 if (handler.ClearAllFn != NULL)
15785 handler.ClearAllFn(&g, &handler);
15786}
15787
15788void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
15789{
15790 size_t file_data_size = 0;
15791 char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
15792 if (!file_data)
15793 return;
15794 if (file_data_size > 0)
15795 LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
15796 IM_FREE(file_data);
15797}
15798
15799// Zero-tolerance, no error reporting, cheap .ini parsing
15800// Set ini_size==0 to let us use strlen(ini_data). Do not call this function with a 0 if your buffer is actually empty!
15801void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
15802{
15803 ImGuiContext& g = *GImGui;
15805 //IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()");
15806 //IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
15807
15808 // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).
15809 // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
15810 if (ini_size == 0)
15811 ini_size = ImStrlen(ini_data);
15812 g.SettingsIniData.Buf.resize((int)ini_size + 1);
15813 char* const buf = g.SettingsIniData.Buf.Data;
15814 char* const buf_end = buf + ini_size;
15815 memcpy(buf, ini_data, ini_size);
15816 buf_end[0] = 0;
15817
15818 // Call pre-read handlers
15819 // Some types will clear their data (e.g. dock information) some types will allow merge/override (window)
15820 for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
15821 if (handler.ReadInitFn != NULL)
15822 handler.ReadInitFn(&g, &handler);
15823
15824 void* entry_data = NULL;
15825 ImGuiSettingsHandler* entry_handler = NULL;
15826
15827 char* line_end = NULL;
15828 for (char* line = buf; line < buf_end; line = line_end + 1)
15829 {
15830 // Skip new lines markers, then find end of the line
15831 while (*line == '\n' || *line == '\r')
15832 line++;
15833 line_end = line;
15834 while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
15835 line_end++;
15836 line_end[0] = 0;
15837 if (line[0] == ';')
15838 continue;
15839 if (line[0] == '[' && line_end > line && line_end[-1] == ']')
15840 {
15841 // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.
15842 line_end[-1] = 0;
15843 const char* name_end = line_end - 1;
15844 const char* type_start = line + 1;
15845 char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']');
15846 const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
15847 if (!type_end || !name_start)
15848 continue;
15849 *type_end = 0; // Overwrite first ']'
15850 name_start++; // Skip second '['
15851 entry_handler = FindSettingsHandler(type_start);
15852 entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
15853 }
15854 else if (entry_handler != NULL && entry_data != NULL)
15855 {
15856 // Let type handler parse the line
15857 entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
15858 }
15859 }
15860 g.SettingsLoaded = true;
15861
15862 // [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary)
15863 memcpy(buf, ini_data, ini_size);
15864
15865 // Call post-read handlers
15866 for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
15867 if (handler.ApplyAllFn != NULL)
15868 handler.ApplyAllFn(&g, &handler);
15869}
15870
15871void ImGui::SaveIniSettingsToDisk(const char* ini_filename)
15872{
15873 ImGuiContext& g = *GImGui;
15874 g.SettingsDirtyTimer = 0.0f;
15875 if (!ini_filename)
15876 return;
15877
15878 size_t ini_data_size = 0;
15879 const char* ini_data = SaveIniSettingsToMemory(&ini_data_size);
15880 ImFileHandle f = ImFileOpen(ini_filename, "wt");
15881 if (!f)
15882 return;
15883 ImFileWrite(ini_data, sizeof(char), ini_data_size, f);
15884 ImFileClose(f);
15885}
15886
15887// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer
15888const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
15889{
15890 ImGuiContext& g = *GImGui;
15891 g.SettingsDirtyTimer = 0.0f;
15894 for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
15895 handler.WriteAllFn(&g, &handler, &g.SettingsIniData);
15896 if (out_size)
15897 *out_size = (size_t)g.SettingsIniData.size();
15898 return g.SettingsIniData.c_str();
15899}
15900
15902{
15903 ImGuiContext& g = *GImGui;
15904
15905 if (g.IO.ConfigDebugIniSettings == false)
15906 {
15907 // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
15908 // Preserve the full string when ConfigDebugVerboseIniSettings is set to make .ini inspection easier.
15909 if (const char* p = strstr(name, "###"))
15910 name = p;
15911 }
15912 const size_t name_len = ImStrlen(name);
15913
15914 // Allocate chunk
15915 const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;
15916 ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);
15918 settings->ID = ImHashStr(name, name_len);
15919 memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator
15920
15921 return settings;
15922}
15923
15924// We don't provide a FindWindowSettingsByName() because Docking system doesn't always hold on names.
15925// This is called once per window .ini entry + once per newly instantiated window.
15927{
15928 ImGuiContext& g = *GImGui;
15929 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
15930 if (settings->ID == id && !settings->WantDelete)
15931 return settings;
15932 return NULL;
15933}
15934
15935// This is faster if you are holding on a Window already as we don't need to perform a search.
15937{
15938 ImGuiContext& g = *GImGui;
15939 if (window->SettingsOffset != -1)
15941 return FindWindowSettingsByID(window->ID);
15942}
15943
15944// This will revert window to its initial state, including enabling the ImGuiCond_FirstUseEver/ImGuiCond_Once conditions once more.
15945void ImGui::ClearWindowSettings(const char* name)
15946{
15947 //IMGUI_DEBUG_LOG("ClearWindowSettings('%s')\n", name);
15948 ImGuiContext& g = *GImGui;
15949 ImGuiWindow* window = FindWindowByName(name);
15950 if (window != NULL)
15951 {
15953 InitOrLoadWindowSettings(window, NULL);
15954 if (window->DockId != 0)
15955 DockContextProcessUndockWindow(&g, window, true);
15956 }
15957 if (ImGuiWindowSettings* settings = window ? FindWindowSettingsByWindow(window) : FindWindowSettingsByID(ImHashStr(name)))
15958 settings->WantDelete = true;
15959}
15960
15962{
15963 ImGuiContext& g = *ctx;
15964 for (ImGuiWindow* window : g.Windows)
15965 window->SettingsOffset = -1;
15967}
15968
15970{
15971 ImGuiID id = ImHashStr(name);
15973 if (settings)
15974 *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry
15975 else
15976 settings = ImGui::CreateNewWindowSettings(name);
15977 settings->ID = id;
15978 settings->WantApply = true;
15979 return (void*)settings;
15980}
15981
15982static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
15983{
15984 ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
15985 int x, y;
15986 int i;
15987 ImU32 u1;
15988 if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) { settings->Pos = ImVec2ih((short)x, (short)y); }
15989 else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); }
15990 else if (sscanf(line, "ViewportId=0x%08X", &u1) == 1) { settings->ViewportId = u1; }
15991 else if (sscanf(line, "ViewportPos=%i,%i", &x, &y) == 2){ settings->ViewportPos = ImVec2ih((short)x, (short)y); }
15992 else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); }
15993 else if (sscanf(line, "IsChild=%d", &i) == 1) { settings->IsChild = (i != 0); }
15994 else if (sscanf(line, "DockId=0x%X,%d", &u1, &i) == 2) { settings->DockId = u1; settings->DockOrder = (short)i; }
15995 else if (sscanf(line, "DockId=0x%X", &u1) == 1) { settings->DockId = u1; settings->DockOrder = -1; }
15996 else if (sscanf(line, "ClassId=0x%X", &u1) == 1) { settings->ClassId = u1; }
15997}
15998
15999// Apply to existing windows (if any)
16001{
16002 ImGuiContext& g = *ctx;
16003 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
16004 if (settings->WantApply)
16005 {
16006 if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID))
16007 ApplyWindowSettings(window, settings);
16008 settings->WantApply = false;
16009 }
16010}
16011
16013{
16014 // Gather data from windows that were active during this session
16015 // (if a window wasn't opened in this session we preserve its settings)
16016 ImGuiContext& g = *ctx;
16017 for (ImGuiWindow* window : g.Windows)
16018 {
16020 continue;
16021
16023 if (!settings)
16024 {
16025 settings = ImGui::CreateNewWindowSettings(window->Name);
16026 window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
16027 }
16028 IM_ASSERT(settings->ID == window->ID);
16029 settings->Pos = ImVec2ih(window->Pos - window->ViewportPos);
16030 settings->Size = ImVec2ih(window->SizeFull);
16031 settings->ViewportId = window->ViewportId;
16032 settings->ViewportPos = ImVec2ih(window->ViewportPos);
16033 IM_ASSERT(window->DockNode == NULL || window->DockNode->ID == window->DockId);
16034 settings->DockId = window->DockId;
16035 settings->ClassId = window->WindowClass.ClassId;
16036 settings->DockOrder = window->DockOrder;
16037 settings->Collapsed = window->Collapsed;
16038 settings->IsChild = (window->RootWindow != window); // Cannot rely on ImGuiWindowFlags_ChildWindow here as docked windows have this set.
16039 settings->WantDelete = false;
16040 }
16041
16042 // Write to text buffer
16043 buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve
16044 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
16045 {
16046 if (settings->WantDelete)
16047 continue;
16048 const char* settings_name = settings->GetName();
16049 buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
16050 if (settings->IsChild)
16051 {
16052 buf->appendf("IsChild=1\n");
16053 buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
16054 }
16055 else
16056 {
16057 if (settings->ViewportId != 0 && settings->ViewportId != ImGui::IMGUI_VIEWPORT_DEFAULT_ID)
16058 {
16059 buf->appendf("ViewportPos=%d,%d\n", settings->ViewportPos.x, settings->ViewportPos.y);
16060 buf->appendf("ViewportId=0x%08X\n", settings->ViewportId);
16061 }
16062 if (settings->Pos.x != 0 || settings->Pos.y != 0 || settings->ViewportId == ImGui::IMGUI_VIEWPORT_DEFAULT_ID)
16063 buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y);
16064 if (settings->Size.x != 0 || settings->Size.y != 0)
16065 buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
16066 buf->appendf("Collapsed=%d\n", settings->Collapsed);
16067 if (settings->DockId != 0)
16068 {
16069 //buf->appendf("TabId=0x%08X\n", ImHashStr("#TAB", 4, settings->ID)); // window->TabId: this is not read back but writing it makes "debugging" the .ini data easier.
16070 if (settings->DockOrder == -1)
16071 buf->appendf("DockId=0x%08X\n", settings->DockId);
16072 else
16073 buf->appendf("DockId=0x%08X,%d\n", settings->DockId, settings->DockOrder);
16074 if (settings->ClassId != 0)
16075 buf->appendf("ClassId=0x%08X\n", settings->ClassId);
16076 }
16077 }
16078 buf->append("\n");
16079 }
16080}
16081
16082//-----------------------------------------------------------------------------
16083// [SECTION] LOCALIZATION
16084//-----------------------------------------------------------------------------
16085
16086void ImGui::LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count)
16087{
16088 ImGuiContext& g = *GImGui;
16089 for (int n = 0; n < count; n++)
16090 g.LocalizationTable[entries[n].Key] = entries[n].Text;
16091}
16092
16093//-----------------------------------------------------------------------------
16094// [SECTION] VIEWPORTS, PLATFORM WINDOWS
16095//-----------------------------------------------------------------------------
16096// - GetMainViewport()
16097// - FindViewportByID()
16098// - FindViewportByPlatformHandle()
16099// - SetCurrentViewport() [Internal]
16100// - SetWindowViewport() [Internal]
16101// - GetWindowAlwaysWantOwnViewport() [Internal]
16102// - UpdateTryMergeWindowIntoHostViewport() [Internal]
16103// - UpdateTryMergeWindowIntoHostViewports() [Internal]
16104// - TranslateWindowsInViewport() [Internal]
16105// - ScaleWindowsInViewport() [Internal]
16106// - FindHoveredViewportFromPlatformWindowStack() [Internal]
16107// - UpdateViewportsNewFrame() [Internal]
16108// - UpdateViewportsEndFrame() [Internal]
16109// - AddUpdateViewport() [Internal]
16110// - WindowSelectViewport() [Internal]
16111// - WindowSyncOwnedViewport() [Internal]
16112// - UpdatePlatformWindows()
16113// - RenderPlatformWindowsDefault()
16114// - FindPlatformMonitorForPos() [Internal]
16115// - FindPlatformMonitorForRect() [Internal]
16116// - UpdateViewportPlatformMonitor() [Internal]
16117// - DestroyPlatformWindow() [Internal]
16118// - DestroyPlatformWindows()
16119//-----------------------------------------------------------------------------
16120
16122{
16123 ImGuiContext& g = *GImGui;
16124 return g.Viewports[0];
16125}
16126
16127// FIXME: This leaks access to viewports not listed in PlatformIO.Viewports[]. Problematic? (#4236)
16129{
16130 ImGuiContext& g = *GImGui;
16131 for (ImGuiViewportP* viewport : g.Viewports)
16132 if (viewport->ID == id)
16133 return viewport;
16134 return NULL;
16135}
16136
16138{
16139 ImGuiContext& g = *GImGui;
16140 for (ImGuiViewportP* viewport : g.Viewports)
16141 if (viewport->PlatformHandle == platform_handle)
16142 return viewport;
16143 return NULL;
16144}
16145
16147{
16148 ImGuiContext& g = *GImGui;
16149 (void)current_window;
16150
16151 if (viewport)
16152 viewport->LastFrameActive = g.FrameCount;
16153 if (g.CurrentViewport == viewport)
16154 return;
16155 g.CurrentDpiScale = viewport ? viewport->DpiScale : 1.0f;
16156 g.CurrentViewport = viewport;
16157 IM_ASSERT(g.CurrentDpiScale > 0.0f && g.CurrentDpiScale < 99.0f); // Typical correct values would be between 1.0f and 4.0f
16158 //IMGUI_DEBUG_LOG_VIEWPORT("[viewport] SetCurrentViewport changed '%s' 0x%08X\n", current_window ? current_window->Name : NULL, viewport ? viewport->ID : 0);
16159
16160 // Notify platform layer of viewport changes
16161 // FIXME-DPI: This is only currently used for experimenting with handling of multiple DPI
16164}
16165
16167{
16168 // Abandon viewport
16169 if (window->ViewportOwned && window->Viewport->Window == window)
16170 window->Viewport->Size = ImVec2(0.0f, 0.0f);
16171
16172 window->Viewport = viewport;
16173 window->ViewportId = viewport->ID;
16174 window->ViewportOwned = (viewport->Window == window);
16175}
16176
16178{
16179 // Tooltips and menus are not automatically forced into their own viewport when the NoMerge flag is set, however the multiplication of viewports makes them more likely to protrude and create their own.
16180 ImGuiContext& g = *GImGui;
16183 if (!window->DockIsActive)
16185 if ((window->Flags & ImGuiWindowFlags_Popup) == 0 || (window->Flags & ImGuiWindowFlags_Modal) != 0)
16186 return true;
16187 return false;
16188}
16189
16191{
16192 ImGuiContext& g = *GImGui;
16193 if (window->Viewport == viewport)
16194 return false;
16195 if ((viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows) == 0)
16196 return false;
16197 if ((viewport->Flags & ImGuiViewportFlags_IsMinimized) != 0)
16198 return false;
16199 if (!viewport->GetMainRect().Contains(window->Rect()))
16200 return false;
16202 return false;
16203
16204 // FIXME: Can't use g.WindowsFocusOrder[] for root windows only as we care about Z order. If we maintained a DisplayOrder along with FocusOrder we could..
16205 for (ImGuiWindow* window_behind : g.Windows)
16206 {
16207 if (window_behind == window)
16208 break;
16209 if (window_behind->WasActive && window_behind->ViewportOwned && !(window_behind->Flags & ImGuiWindowFlags_ChildWindow))
16210 if (window_behind->Viewport->GetMainRect().Overlaps(window->Rect()))
16211 return false;
16212 }
16213
16214 // Move to the existing viewport, Move child/hosted windows as well (FIXME-OPT: iterate child)
16215 ImGuiViewportP* old_viewport = window->Viewport;
16216 if (window->ViewportOwned)
16217 for (int n = 0; n < g.Windows.Size; n++)
16218 if (g.Windows[n]->Viewport == old_viewport)
16219 SetWindowViewport(g.Windows[n], viewport);
16220 SetWindowViewport(window, viewport);
16222
16223 return true;
16224}
16225
16226// FIXME: handle 0 to N host viewports
16228{
16229 ImGuiContext& g = *GImGui;
16231}
16232
16233// Translate Dear ImGui windows when a Host Viewport has been moved
16234// (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!)
16235void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos, const ImVec2& old_size, const ImVec2& new_size)
16236{
16237 ImGuiContext& g = *GImGui;
16238 //IMGUI_DEBUG_LOG_VIEWPORT("[viewport] TranslateWindowsInViewport 0x%08X\n", viewport->ID);
16239 IM_ASSERT(viewport->Window == NULL && (viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows));
16240
16241 // 1) We test if ImGuiConfigFlags_ViewportsEnable was just toggled, which allows us to conveniently
16242 // translate imgui windows from OS-window-local to absolute coordinates or vice-versa.
16243 // 2) If it's not going to fit into the new size, keep it at same absolute position.
16244 // One problem with this is that most Win32 applications doesn't update their render while dragging,
16245 // and so the window will appear to teleport when releasing the mouse.
16247 ImRect test_still_fit_rect(old_pos, old_pos + old_size);
16248 ImVec2 delta_pos = new_pos - old_pos;
16249 for (ImGuiWindow* window : g.Windows) // FIXME-OPT
16250 if (translate_all_windows || (window->Viewport == viewport && (old_size == new_size || test_still_fit_rect.Contains(window->Rect()))))
16251 TranslateWindow(window, delta_pos);
16252}
16253
16254// Scale all windows (position, size). Use when e.g. changing DPI. (This is a lossy operation!)
16256{
16257 ImGuiContext& g = *GImGui;
16258 //IMGUI_DEBUG_LOG_VIEWPORT("[viewport] ScaleWindowsInViewport 0x%08X\n", viewport->ID);
16259 if (viewport->Window)
16260 {
16261 ScaleWindow(viewport->Window, scale);
16262 }
16263 else
16264 {
16265 for (ImGuiWindow* window : g.Windows)
16266 if (window->Viewport == viewport)
16267 ScaleWindow(window, scale);
16268 }
16269}
16270
16271// If the backend doesn't set MouseLastHoveredViewport or doesn't honor ImGuiViewportFlags_NoInputs, we do a search ourselves.
16272// A) It won't take account of the possibility that non-imgui windows may be in-between our dragged window and our target window.
16273// B) It requires Platform_GetWindowFocus to be implemented by backend.
16275{
16276 ImGuiContext& g = *GImGui;
16277 ImGuiViewportP* best_candidate = NULL;
16278 for (ImGuiViewportP* viewport : g.Viewports)
16279 if (!(viewport->Flags & (ImGuiViewportFlags_NoInputs | ImGuiViewportFlags_IsMinimized)) && viewport->GetMainRect().Contains(mouse_platform_pos))
16280 if (best_candidate == NULL || best_candidate->LastFocusedStampCount < viewport->LastFocusedStampCount)
16281 best_candidate = viewport;
16282 return best_candidate;
16283}
16284
16285// Update viewports and monitor infos
16286// Note that this is running even if 'ImGuiConfigFlags_ViewportsEnable' is not set, in order to clear unused viewports (if any) and update monitor info.
16288{
16289 ImGuiContext& g = *GImGui;
16291
16292 // Update Minimized status (we need it first in order to decide if we'll apply Pos/Size of the main viewport)
16293 // Update Focused status
16294 const bool viewports_enabled = (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable) != 0;
16295 if (viewports_enabled)
16296 {
16297 ImGuiViewportP* focused_viewport = NULL;
16298 for (ImGuiViewportP* viewport : g.Viewports)
16299 {
16300 const bool platform_funcs_available = viewport->PlatformWindowCreated;
16301 if (g.PlatformIO.Platform_GetWindowMinimized && platform_funcs_available)
16302 {
16303 bool is_minimized = g.PlatformIO.Platform_GetWindowMinimized(viewport);
16304 if (is_minimized)
16306 else
16307 viewport->Flags &= ~ImGuiViewportFlags_IsMinimized;
16308 }
16309
16310 // Update our implicit z-order knowledge of platform windows, which is used when the backend cannot provide io.MouseHoveredViewport.
16311 // When setting Platform_GetWindowFocus, it is expected that the platform backend can handle calls without crashing if it doesn't have data stored.
16312 if (g.PlatformIO.Platform_GetWindowFocus && platform_funcs_available)
16313 {
16314 bool is_focused = g.PlatformIO.Platform_GetWindowFocus(viewport);
16315 if (is_focused)
16317 else
16318 viewport->Flags &= ~ImGuiViewportFlags_IsFocused;
16319 if (is_focused)
16320 focused_viewport = viewport;
16321 }
16322 }
16323
16324 // Focused viewport has changed?
16325 if (focused_viewport && g.PlatformLastFocusedViewportId != focused_viewport->ID)
16326 {
16327 IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Focused viewport changed %08X -> %08X '%s', attempting to apply our focus.\n", g.PlatformLastFocusedViewportId, focused_viewport->ID, focused_viewport->Window ? focused_viewport->Window->Name : "n/a");
16328 const ImGuiViewport* prev_focused_viewport = FindViewportByID(g.PlatformLastFocusedViewportId);
16329 const bool prev_focused_has_been_destroyed = (prev_focused_viewport == NULL) || (prev_focused_viewport->PlatformWindowCreated == false);
16330
16331 // Store a tag so we can infer z-order easily from all our windows
16332 // We compare PlatformLastFocusedViewportId so newly created viewports with _NoFocusOnAppearing flag
16333 // will keep the front most stamp instead of losing it back to their parent viewport.
16334 if (focused_viewport->LastFocusedStampCount != g.ViewportFocusedStampCount)
16335 focused_viewport->LastFocusedStampCount = ++g.ViewportFocusedStampCount;
16336 g.PlatformLastFocusedViewportId = focused_viewport->ID;
16337
16338 // Focus associated dear imgui window
16339 // - if focus didn't happen with a click within imgui boundaries, e.g. Clicking platform title bar. (#6299)
16340 // - if focus didn't happen because we destroyed another window (#6462)
16341 // FIXME: perhaps 'FocusTopMostWindowUnderOne()' can handle the 'focused_window->Window != NULL' case as well.
16342 const bool apply_imgui_focus_on_focused_viewport = !IsAnyMouseDown() && !prev_focused_has_been_destroyed;
16343 if (apply_imgui_focus_on_focused_viewport)
16344 {
16345 focused_viewport->LastFocusedHadNavWindow |= (g.NavWindow != NULL) && (g.NavWindow->Viewport == focused_viewport); // Update so a window changing viewport won't lose focus.
16347 if (focused_viewport->Window != NULL)
16348 FocusWindow(focused_viewport->Window, focus_request_flags);
16349 else if (focused_viewport->LastFocusedHadNavWindow)
16350 FocusTopMostWindowUnderOne(NULL, NULL, focused_viewport, focus_request_flags); // Focus top most in viewport
16351 else
16352 FocusWindow(NULL, focus_request_flags); // No window had focus last time viewport was focused
16353 }
16354 }
16355 if (focused_viewport)
16356 focused_viewport->LastFocusedHadNavWindow = (g.NavWindow != NULL) && (g.NavWindow->Viewport == focused_viewport);
16357 }
16358
16359 // Create/update main viewport with current platform position.
16360 // FIXME-VIEWPORT: Size is driven by backend/user code for backward-compatibility but we should aim to make this more consistent.
16361 ImGuiViewportP* main_viewport = g.Viewports[0];
16362 IM_ASSERT(main_viewport->ID == IMGUI_VIEWPORT_DEFAULT_ID);
16363 IM_ASSERT(main_viewport->Window == NULL);
16364 ImVec2 main_viewport_pos = viewports_enabled ? g.PlatformIO.Platform_GetWindowPos(main_viewport) : ImVec2(0.0f, 0.0f);
16365 ImVec2 main_viewport_size = g.IO.DisplaySize;
16366 ImVec2 main_viewport_framebuffer_scale = g.IO.DisplayFramebufferScale;
16367 if (viewports_enabled && (main_viewport->Flags & ImGuiViewportFlags_IsMinimized))
16368 {
16369 main_viewport_pos = main_viewport->Pos; // Preserve last pos/size when minimized (FIXME: We don't do the same for Size outside of the viewport path)
16370 main_viewport_size = main_viewport->Size;
16371 main_viewport_framebuffer_scale = main_viewport->FramebufferScale;
16372 }
16374
16375 g.CurrentDpiScale = 0.0f;
16376 g.CurrentViewport = NULL;
16377 g.MouseViewport = NULL;
16378 for (int n = 0; n < g.Viewports.Size; n++)
16379 {
16380 ImGuiViewportP* viewport = g.Viewports[n];
16381 viewport->Idx = n;
16382
16383 // Erase unused viewports
16384 if (n > 0 && viewport->LastFrameActive < g.FrameCount - 2)
16385 {
16386 DestroyViewport(viewport);
16387 n--;
16388 continue;
16389 }
16390
16391 const bool platform_funcs_available = viewport->PlatformWindowCreated;
16392 if (viewports_enabled)
16393 {
16394 // Update Position and Size (from Platform Window to ImGui) if requested.
16395 // We do it early in the frame instead of waiting for UpdatePlatformWindows() to avoid a frame of lag when moving/resizing using OS facilities.
16396 if (!(viewport->Flags & ImGuiViewportFlags_IsMinimized) && platform_funcs_available)
16397 {
16398 // Viewport->WorkPos and WorkSize will be updated below
16399 if (viewport->PlatformRequestMove)
16400 viewport->Pos = viewport->LastPlatformPos = g.PlatformIO.Platform_GetWindowPos(viewport);
16401 if (viewport->PlatformRequestResize)
16402 viewport->Size = viewport->LastPlatformSize = g.PlatformIO.Platform_GetWindowSize(viewport);
16405 }
16406 }
16407
16408 // Update/copy monitor info
16410
16411 // Lock down space taken by menu bars and status bars + query initial insets from backend
16412 // Setup initial value for functions like BeginMainMenuBar(), DockSpaceOverViewport() etc.
16413 viewport->WorkInsetMin = viewport->BuildWorkInsetMin;
16414 viewport->WorkInsetMax = viewport->BuildWorkInsetMax;
16415 viewport->BuildWorkInsetMin = viewport->BuildWorkInsetMax = ImVec2(0.0f, 0.0f);
16416 if (g.PlatformIO.Platform_GetWindowWorkAreaInsets != NULL && platform_funcs_available)
16417 {
16419 IM_ASSERT(insets.x >= 0.0f && insets.y >= 0.0f && insets.z >= 0.0f && insets.w >= 0.0f);
16420 viewport->BuildWorkInsetMin = ImVec2(insets.x, insets.y);
16421 viewport->BuildWorkInsetMax = ImVec2(insets.z, insets.w);
16422 }
16423 viewport->UpdateWorkRect();
16424
16425 // Reset alpha every frame. Users of transparency (docking) needs to request a lower alpha back.
16426 viewport->Alpha = 1.0f;
16427
16428 // Translate Dear ImGui windows when a Host Viewport has been moved
16429 // (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!)
16430 const ImVec2 viewport_delta_pos = viewport->Pos - viewport->LastPos;
16431 if ((viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows) && (viewport_delta_pos.x != 0.0f || viewport_delta_pos.y != 0.0f))
16432 TranslateWindowsInViewport(viewport, viewport->LastPos, viewport->Pos, viewport->LastSize, viewport->Size);
16433
16434 // Update DPI scale
16435 float new_dpi_scale;
16436 if (g.PlatformIO.Platform_GetWindowDpiScale && platform_funcs_available)
16437 new_dpi_scale = g.PlatformIO.Platform_GetWindowDpiScale(viewport);
16438 else if (viewport->PlatformMonitor != -1)
16439 new_dpi_scale = g.PlatformIO.Monitors[viewport->PlatformMonitor].DpiScale;
16440 else
16441 new_dpi_scale = (viewport->DpiScale != 0.0f) ? viewport->DpiScale : 1.0f;
16442 IM_ASSERT(new_dpi_scale > 0.0f && new_dpi_scale < 99.0f); // Typical correct values would be between 1.0f and 4.0f
16443 if (viewport->DpiScale != 0.0f && new_dpi_scale != viewport->DpiScale)
16444 {
16445 float scale_factor = new_dpi_scale / viewport->DpiScale;
16447 ScaleWindowsInViewport(viewport, scale_factor);
16448 //if (viewport == GetMainViewport())
16449 // g.PlatformInterface.SetWindowSize(viewport, viewport->Size * scale_factor);
16450
16451 // Scale our window moving pivot so that the window will rescale roughly around the mouse position.
16452 // FIXME-VIEWPORT: This currently creates a resizing feedback loop when a window is straddling a DPI transition border.
16453 // (Minor: since our sizes do not perfectly linearly scale, deferring the click offset scale until we know the actual window scale ratio may get us slightly more precise mouse positioning.)
16454 //if (g.MovingWindow != NULL && g.MovingWindow->Viewport == viewport)
16455 // g.ActiveIdClickOffset = ImTrunc(g.ActiveIdClickOffset * scale_factor);
16456 }
16457 viewport->DpiScale = new_dpi_scale;
16458 }
16459
16460 // Update fallback monitor
16461 g.PlatformMonitorsFullWorkRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);
16462 if (g.PlatformIO.Monitors.Size == 0)
16463 {
16465 monitor->MainPos = main_viewport->Pos;
16466 monitor->MainSize = main_viewport->Size;
16467 monitor->WorkPos = main_viewport->WorkPos;
16468 monitor->WorkSize = main_viewport->WorkSize;
16469 monitor->DpiScale = main_viewport->DpiScale;
16471 g.PlatformMonitorsFullWorkRect.Add(monitor->WorkPos + monitor->WorkSize);
16472 }
16473 else
16474 {
16476 }
16477 for (ImGuiPlatformMonitor& monitor : g.PlatformIO.Monitors)
16478 {
16480 g.PlatformMonitorsFullWorkRect.Add(monitor.WorkPos + monitor.WorkSize);
16481 }
16482
16483 if (!viewports_enabled)
16484 {
16485 g.MouseViewport = main_viewport;
16486 return;
16487 }
16488
16489 // Mouse handling: decide on the actual mouse viewport for this frame between the active/focused viewport and the hovered viewport.
16490 // Note that 'viewport_hovered' should skip over any viewport that has the ImGuiViewportFlags_NoInputs flags set.
16491 ImGuiViewportP* viewport_hovered = NULL;
16493 {
16495 if (viewport_hovered && (viewport_hovered->Flags & ImGuiViewportFlags_NoInputs))
16496 viewport_hovered = FindHoveredViewportFromPlatformWindowStack(g.IO.MousePos); // Backend failed to handle _NoInputs viewport: revert to our fallback.
16497 }
16498 else
16499 {
16500 // If the backend doesn't know how to honor ImGuiViewportFlags_NoInputs, we do a search ourselves. Note that this search:
16501 // A) won't take account of the possibility that non-imgui windows may be in-between our dragged window and our target window.
16502 // B) won't take account of how the backend apply parent<>child relationship to secondary viewports, which affects their Z order.
16503 // C) uses LastFrameAsRefViewport as a flawed replacement for the last time a window was focused (we could/should fix that by introducing Focus functions in PlatformIO)
16505 }
16506 if (viewport_hovered != NULL)
16507 g.MouseLastHoveredViewport = viewport_hovered;
16508 else if (g.MouseLastHoveredViewport == NULL)
16510
16511 // Update mouse reference viewport
16512 // (when moving a window we aim at its viewport, but this will be overwritten below if we go in drag and drop mode)
16513 // (MovingViewport->Viewport will be NULL in the rare situation where the window disappared while moving, set UpdateMouseMovingWindowNewFrame() for details)
16516 else
16518
16519 // When dragging something, always refer to the last hovered viewport.
16520 // - when releasing a moving window we will revert to aiming behind (at viewport_hovered)
16521 // - when we are between viewports, our dragged preview will tend to show in the last viewport _even_ if we don't have tooltips in their viewports (when lacking monitor info)
16522 // - consider the case of holding on a menu item to browse child menus: even thou a mouse button is held, there's no active id because menu items only react on mouse release.
16523 // FIXME-VIEWPORT: This is essentially broken, when ImGuiBackendFlags_HasMouseHoveredViewport is set we want to trust when viewport_hovered==NULL and use that.
16524 const bool is_mouse_dragging_with_an_expected_destination = g.DragDropActive;
16525 if (is_mouse_dragging_with_an_expected_destination && viewport_hovered == NULL)
16526 viewport_hovered = g.MouseLastHoveredViewport;
16527 if (is_mouse_dragging_with_an_expected_destination || g.ActiveId == 0 || !IsAnyMouseDown())
16528 if (viewport_hovered != NULL && viewport_hovered != g.MouseViewport && !(viewport_hovered->Flags & ImGuiViewportFlags_NoInputs))
16529 g.MouseViewport = viewport_hovered;
16530
16531 IM_ASSERT(g.MouseViewport != NULL);
16532}
16533
16534// Update user-facing viewport list (g.Viewports -> g.PlatformIO.Viewports after filtering out some)
16536{
16537 ImGuiContext& g = *GImGui;
16539 for (int i = 0; i < g.Viewports.Size; i++)
16540 {
16541 ImGuiViewportP* viewport = g.Viewports[i];
16542 viewport->LastPos = viewport->Pos;
16543 viewport->LastSize = viewport->Size;
16544 if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f)
16545 if (i > 0) // Always include main viewport in the list
16546 continue;
16547 if (viewport->Window && !IsWindowActiveAndVisible(viewport->Window))
16548 continue;
16549 if (i > 0)
16550 IM_ASSERT(viewport->Window != NULL);
16551 g.PlatformIO.Viewports.push_back(viewport);
16552 }
16553 g.Viewports[0]->ClearRequestFlags(); // Clear main viewport flags because UpdatePlatformWindows() won't do it and may not even be called
16554}
16555
16556// FIXME: We should ideally refactor the system to call this every frame (we currently don't)
16558{
16559 ImGuiContext& g = *GImGui;
16560 IM_ASSERT(id != 0);
16561
16563 if (window != NULL)
16564 {
16565 if (g.MovingWindow && g.MovingWindow->RootWindowDockTree == window)
16571 }
16572
16574 if (viewport)
16575 {
16576 // Always update for main viewport as we are already pulling correct platform pos/size (see #4900)
16577 ImVec2 prev_pos = viewport->Pos;
16578 ImVec2 prev_size = viewport->Size;
16579 if (!viewport->PlatformRequestMove || viewport->ID == IMGUI_VIEWPORT_DEFAULT_ID)
16580 viewport->Pos = pos;
16581 if (!viewport->PlatformRequestResize || viewport->ID == IMGUI_VIEWPORT_DEFAULT_ID)
16582 viewport->Size = size;
16583 viewport->Flags = flags | (viewport->Flags & (ImGuiViewportFlags_IsMinimized | ImGuiViewportFlags_IsFocused)); // Preserve existing flags
16584 if (prev_pos != viewport->Pos || prev_size != viewport->Size)
16586 }
16587 else
16588 {
16589 // New viewport
16590 viewport = IM_NEW(ImGuiViewportP)();
16591 viewport->ID = id;
16592 viewport->Idx = g.Viewports.Size;
16593 viewport->Pos = viewport->LastPos = pos;
16594 viewport->Size = viewport->LastSize = size;
16595 viewport->Flags = flags;
16597 g.Viewports.push_back(viewport);
16599 IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Add Viewport %08X '%s'\n", id, window ? window->Name : "<NULL>");
16600
16601 // We normally setup for all viewports in NewFrame() but here need to handle the mid-frame creation of a new viewport.
16602 // We need to extend the fullscreen clip rect so the OverlayDrawList clip is correct for that the first frame
16607
16608 // Store initial DpiScale before the OS platform window creation, based on expected monitor data.
16609 // This is so we can select an appropriate font size on the first frame of our window lifetime
16610 viewport->DpiScale = GetViewportPlatformMonitor(viewport)->DpiScale;
16611 }
16612
16613 viewport->Window = window;
16614 viewport->LastFrameActive = g.FrameCount;
16615 viewport->UpdateWorkRect();
16616 IM_ASSERT(window == NULL || viewport->ID == window->ID);
16617
16618 if (window != NULL)
16619 window->ViewportOwned = true;
16620
16621 return viewport;
16622}
16623
16625{
16626 // Clear references to this viewport in windows (window->ViewportId becomes the master data)
16627 ImGuiContext& g = *GImGui;
16628 for (ImGuiWindow* window : g.Windows)
16629 {
16630 if (window->Viewport != viewport)
16631 continue;
16632 window->Viewport = NULL;
16633 window->ViewportOwned = false;
16634 }
16635 if (viewport == g.MouseLastHoveredViewport)
16636 g.MouseLastHoveredViewport = NULL;
16637
16638 // Destroy
16639 IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Delete Viewport %08X '%s'\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a");
16640 DestroyPlatformWindow(viewport); // In most circumstances the platform window will already be destroyed here.
16641 IM_ASSERT(g.PlatformIO.Viewports.contains(viewport) == false);
16642 IM_ASSERT(g.Viewports[viewport->Idx] == viewport);
16643 g.Viewports.erase(g.Viewports.Data + viewport->Idx);
16644 IM_DELETE(viewport);
16645}
16646
16647// FIXME-VIEWPORT: This is all super messy and ought to be clarified or rewritten.
16649{
16650 ImGuiContext& g = *GImGui;
16651 ImGuiWindowFlags flags = window->Flags;
16653
16654 // Restore main viewport if multi-viewport is not supported by the backend
16655 ImGuiViewportP* main_viewport = (ImGuiViewportP*)(void*)GetMainViewport();
16657 {
16658 SetWindowViewport(window, main_viewport);
16659 return;
16660 }
16661 window->ViewportOwned = false;
16662
16663 // Appearing popups reset their viewport so they can inherit again
16664 if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && window->Appearing)
16665 {
16666 window->Viewport = NULL;
16667 window->ViewportId = 0;
16668 }
16669
16671 {
16672 // By default inherit from parent window
16673 if (window->Viewport == NULL && window->ParentWindow && (!window->ParentWindow->IsFallbackWindow || window->ParentWindow->WasActive))
16674 window->Viewport = window->ParentWindow->Viewport;
16675
16676 // Attempt to restore saved viewport id (= window that hasn't been activated yet), try to restore the viewport based on saved 'window->ViewportPos' restored from .ini file
16677 if (window->Viewport == NULL && window->ViewportId != 0)
16678 {
16680 if (window->Viewport == NULL && window->ViewportPos.x != FLT_MAX && window->ViewportPos.y != FLT_MAX)
16681 window->Viewport = AddUpdateViewport(window, window->ID, window->ViewportPos, window->Size, ImGuiViewportFlags_None);
16682 }
16683 }
16684
16685 bool lock_viewport = false;
16687 {
16688 // Code explicitly request a viewport
16690 window->ViewportId = g.NextWindowData.ViewportId; // Store ID even if Viewport isn't resolved yet.
16691 if (window->Viewport && (window->Flags & ImGuiWindowFlags_DockNodeHost) != 0 && window->Viewport->Window != NULL)
16692 {
16693 window->Viewport->Window = window;
16694 window->Viewport->ID = window->ViewportId = window->ID; // Overwrite ID (always owned by node)
16695 }
16696 lock_viewport = true;
16697 }
16698 else if ((flags & ImGuiWindowFlags_ChildWindow) || (flags & ImGuiWindowFlags_ChildMenu))
16699 {
16700 // Always inherit viewport from parent window
16701 if (window->DockNode && window->DockNode->HostWindow)
16703 window->Viewport = window->ParentWindow->Viewport;
16704 }
16705 else if (window->DockNode && window->DockNode->HostWindow)
16706 {
16707 // This covers the "always inherit viewport from parent window" case for when a window reattach to a node that was just created mid-frame
16708 window->Viewport = window->DockNode->HostWindow->Viewport;
16709 }
16710 else if (flags & ImGuiWindowFlags_Tooltip)
16711 {
16712 window->Viewport = g.MouseViewport;
16713 }
16714 else if (GetWindowAlwaysWantOwnViewport(window))
16715 {
16716 window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_None);
16717 }
16718 else if (g.MovingWindow && g.MovingWindow->RootWindowDockTree == window && IsMousePosValid())
16719 {
16720 if (window->Viewport != NULL && window->Viewport->Window == window)
16721 window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_None);
16722 }
16723 else
16724 {
16725 // Merge into host viewport?
16726 // We cannot test window->ViewportOwned as it set lower in the function.
16727 // Testing (g.ActiveId == 0 || g.ActiveIdAllowOverlap) to avoid merging during a short-term widget interaction. Main intent was to avoid during resize (see #4212)
16728 bool try_to_merge_into_host_viewport = (window->Viewport && window == window->Viewport->Window && (g.ActiveId == 0 || g.ActiveIdAllowOverlap));
16729 if (try_to_merge_into_host_viewport)
16731 }
16732
16733 // Fallback: merge in default viewport if z-order matches, otherwise create a new viewport
16734 if (window->Viewport == NULL)
16735 if (!UpdateTryMergeWindowIntoHostViewport(window, main_viewport))
16736 window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_None);
16737
16738 // Mark window as allowed to protrude outside of its viewport and into the current monitor
16739 if (!lock_viewport)
16740 {
16742 {
16743 // We need to take account of the possibility that mouse may become invalid.
16744 // Popups/Tooltip always set ViewportAllowPlatformMonitorExtend so GetWindowAllowedExtentRect() will return full monitor bounds.
16746 bool use_mouse_ref = (!g.NavCursorVisible || !g.NavHighlightItemUnderNav || !g.NavWindow);
16747 bool mouse_valid = IsMousePosValid(&mouse_ref);
16748 if ((window->Appearing || (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_ChildMenu))) && (!use_mouse_ref || mouse_valid))
16749 window->ViewportAllowPlatformMonitorExtend = FindPlatformMonitorForPos((use_mouse_ref && mouse_valid) ? mouse_ref : NavCalcPreferredRefPos());
16750 else
16752 }
16753 else if (window->Viewport && window != window->Viewport->Window && window->Viewport->Window && !(flags & ImGuiWindowFlags_ChildWindow) && window->DockNode == NULL)
16754 {
16755 // When called from Begin() we don't have access to a proper version of the Hidden flag yet, so we replicate this code.
16756 const bool will_be_visible = (window->DockIsActive && !window->DockTabIsVisible) ? false : true;
16757 if ((window->Flags & ImGuiWindowFlags_DockNodeHost) && window->Viewport->LastFrameActive < g.FrameCount && will_be_visible)
16758 {
16759 // Steal/transfer ownership
16760 IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Window '%s' steal Viewport %08X from Window '%s'\n", window->Name, window->Viewport->ID, window->Viewport->Window->Name);
16761 window->Viewport->Window = window;
16762 window->Viewport->ID = window->ID;
16763 window->Viewport->LastNameHash = 0;
16764 }
16765 else if (!UpdateTryMergeWindowIntoHostViewports(window)) // Merge?
16766 {
16767 // New viewport
16768 window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_NoFocusOnAppearing);
16769 }
16770 }
16771 else if (window->ViewportAllowPlatformMonitorExtend < 0 && (flags & ImGuiWindowFlags_ChildWindow) == 0)
16772 {
16773 // Regular (non-child, non-popup) windows by default are also allowed to protrude
16774 // Child windows are kept contained within their parent.
16776 }
16777 }
16778
16779 // Update flags
16780 window->ViewportOwned = (window == window->Viewport->Window);
16781 window->ViewportId = window->Viewport->ID;
16782
16783 // If the OS window has a title bar, hide our imgui title bar
16784 //if (window->ViewportOwned && !(window->Viewport->Flags & ImGuiViewportFlags_NoDecoration))
16785 // window->Flags |= ImGuiWindowFlags_NoTitleBar;
16786}
16787
16788void ImGui::WindowSyncOwnedViewport(ImGuiWindow* window, ImGuiWindow* parent_window_in_stack)
16789{
16790 ImGuiContext& g = *GImGui;
16791
16792 bool viewport_rect_changed = false;
16793
16794 // Synchronize window --> viewport in most situations
16795 // Synchronize viewport -> window in case the platform window has been moved or resized from the OS/WM
16796 if (window->Viewport->PlatformRequestMove)
16797 {
16798 window->Pos = window->Viewport->Pos;
16799 MarkIniSettingsDirty(window);
16800 }
16801 else if (memcmp(&window->Viewport->Pos, &window->Pos, sizeof(window->Pos)) != 0)
16802 {
16803 viewport_rect_changed = true;
16804 window->Viewport->Pos = window->Pos;
16805 }
16806
16807 if (window->Viewport->PlatformRequestResize)
16808 {
16809 window->Size = window->SizeFull = window->Viewport->Size;
16810 MarkIniSettingsDirty(window);
16811 }
16812 else if (memcmp(&window->Viewport->Size, &window->Size, sizeof(window->Size)) != 0)
16813 {
16814 viewport_rect_changed = true;
16815 window->Viewport->Size = window->Size;
16816 }
16817 window->Viewport->UpdateWorkRect();
16818
16819 // The viewport may have changed monitor since the global update in UpdateViewportsNewFrame()
16820 // Either a SetNextWindowPos() call in the current frame or a SetWindowPos() call in the previous frame may have this effect.
16821 if (viewport_rect_changed)
16823
16824 // Update common viewport flags
16826 ImGuiViewportFlags viewport_flags = window->Viewport->Flags & ~viewport_flags_to_clear;
16827 ImGuiWindowFlags window_flags = window->Flags;
16828 const bool is_modal = (window_flags & ImGuiWindowFlags_Modal) != 0;
16829 const bool is_short_lived_floating_window = (window_flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0;
16830 if (window_flags & ImGuiWindowFlags_Tooltip)
16831 viewport_flags |= ImGuiViewportFlags_TopMost;
16832 if ((g.IO.ConfigViewportsNoTaskBarIcon || is_short_lived_floating_window) && !is_modal)
16833 viewport_flags |= ImGuiViewportFlags_NoTaskBarIcon;
16834 if (g.IO.ConfigViewportsNoDecoration || is_short_lived_floating_window)
16835 viewport_flags |= ImGuiViewportFlags_NoDecoration;
16836
16837 // Not correct to set modal as topmost because:
16838 // - Because other popups can be stacked above a modal (e.g. combo box in a modal)
16839 // - ImGuiViewportFlags_TopMost is currently handled different in backends: in Win32 it is "appear top most" whereas in GLFW and SDL it is "stay topmost"
16840 //if (flags & ImGuiWindowFlags_Modal)
16841 // viewport_flags |= ImGuiViewportFlags_TopMost;
16842
16843 // For popups and menus that may be protruding out of their parent viewport, we enable _NoFocusOnClick so that clicking on them
16844 // won't steal the OS focus away from their parent window (which may be reflected in OS the title bar decoration).
16845 // Setting _NoFocusOnClick would technically prevent us from bringing back to front in case they are being covered by an OS window from a different app,
16846 // but it shouldn't be much of a problem considering those are already popups that are closed when clicking elsewhere.
16847 if (is_short_lived_floating_window && !is_modal)
16849
16850 // We can overwrite viewport flags using ImGuiWindowClass (advanced users)
16852 viewport_flags |= window->WindowClass.ViewportFlagsOverrideSet;
16854 viewport_flags &= ~window->WindowClass.ViewportFlagsOverrideClear;
16855
16856 // We can also tell the backend that clearing the platform window won't be necessary,
16857 // as our window background is filling the viewport and we have disabled BgAlpha.
16858 // FIXME: Work on support for per-viewport transparency (#2766)
16859 if (!(window_flags & ImGuiWindowFlags_NoBackground))
16860 viewport_flags |= ImGuiViewportFlags_NoRendererClear;
16861
16862 window->Viewport->Flags = viewport_flags;
16863
16864 // Update parent viewport ID
16865 // (the !IsFallbackWindow test mimic the one done in WindowSelectViewport())
16866 if (window->WindowClass.ParentViewportId != (ImGuiID)-1)
16868 else if ((window_flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && parent_window_in_stack && (!parent_window_in_stack->IsFallbackWindow || parent_window_in_stack->WasActive))
16869 window->Viewport->ParentViewportId = parent_window_in_stack->Viewport->ID;
16870 else
16872}
16873
16874// Called by user at the end of the main loop, after EndFrame()
16875// This will handle the creation/update of all OS windows via function defined in the ImGuiPlatformIO api.
16877{
16878 ImGuiContext& g = *GImGui;
16879 IM_ASSERT(g.FrameCountEnded == g.FrameCount && "Forgot to call Render() or EndFrame() before UpdatePlatformWindows()?");
16883 return;
16884
16885 // Create/resize/destroy platform windows to match each active viewport.
16886 // Skip the main viewport (index 0), which is always fully handled by the application!
16887 for (int i = 1; i < g.Viewports.Size; i++)
16888 {
16889 ImGuiViewportP* viewport = g.Viewports[i];
16890
16891 // Destroy platform window if the viewport hasn't been submitted or if it is hosting a hidden window
16892 // (the implicit/fallback Debug##Default window will be registering its viewport then be disabled, causing a dummy DestroyPlatformWindow to be made each frame)
16893 bool destroy_platform_window = false;
16894 destroy_platform_window |= (viewport->LastFrameActive < g.FrameCount - 1);
16895 destroy_platform_window |= (viewport->Window && !IsWindowActiveAndVisible(viewport->Window));
16896 if (destroy_platform_window)
16897 {
16898 DestroyPlatformWindow(viewport);
16899 continue;
16900 }
16901
16902 // New windows that appears directly in a new viewport won't always have a size on their first frame
16903 if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0 || viewport->Size.y <= 0)
16904 continue;
16905
16906 // Create window
16907 const bool is_new_platform_window = (viewport->PlatformWindowCreated == false);
16908 if (is_new_platform_window)
16909 {
16910 IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Create Platform Window %08X '%s'\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a");
16912 if (g.PlatformIO.Renderer_CreateWindow != NULL)
16915 viewport->LastNameHash = 0;
16916 viewport->LastPlatformPos = viewport->LastPlatformSize = ImVec2(FLT_MAX, FLT_MAX); // By clearing those we'll enforce a call to Platform_SetWindowPos/Size below, before Platform_ShowWindow (FIXME: Is that necessary?)
16917 viewport->LastRendererSize = viewport->Size; // We don't need to call Renderer_SetWindowSize() as it is expected Renderer_CreateWindow() already did it.
16918 viewport->PlatformWindowCreated = true;
16919 }
16920
16921 // Apply Position and Size (from ImGui to Platform/Renderer backends)
16922 if ((viewport->LastPlatformPos.x != viewport->Pos.x || viewport->LastPlatformPos.y != viewport->Pos.y) && !viewport->PlatformRequestMove)
16923 g.PlatformIO.Platform_SetWindowPos(viewport, viewport->Pos);
16924 if ((viewport->LastPlatformSize.x != viewport->Size.x || viewport->LastPlatformSize.y != viewport->Size.y) && !viewport->PlatformRequestResize)
16925 g.PlatformIO.Platform_SetWindowSize(viewport, viewport->Size);
16926 if ((viewport->LastRendererSize.x != viewport->Size.x || viewport->LastRendererSize.y != viewport->Size.y) && g.PlatformIO.Renderer_SetWindowSize)
16927 g.PlatformIO.Renderer_SetWindowSize(viewport, viewport->Size);
16928 viewport->LastPlatformPos = viewport->Pos;
16929 viewport->LastPlatformSize = viewport->LastRendererSize = viewport->Size;
16930
16931 // Update title bar (if it changed)
16932 if (ImGuiWindow* window_for_title = GetWindowForTitleDisplay(viewport->Window))
16933 {
16934 const char* title_begin = window_for_title->Name;
16935 char* title_end = (char*)(intptr_t)FindRenderedTextEnd(title_begin);
16936 const ImGuiID title_hash = ImHashStr(title_begin, title_end - title_begin);
16937 if (viewport->LastNameHash != title_hash)
16938 {
16939 char title_end_backup_c = *title_end;
16940 *title_end = 0; // Cut existing buffer short instead of doing an alloc/free, no small gain.
16941 g.PlatformIO.Platform_SetWindowTitle(viewport, title_begin);
16942 *title_end = title_end_backup_c;
16943 viewport->LastNameHash = title_hash;
16944 }
16945 }
16946
16947 // Update alpha (if it changed)
16948 if (viewport->LastAlpha != viewport->Alpha && g.PlatformIO.Platform_SetWindowAlpha)
16949 g.PlatformIO.Platform_SetWindowAlpha(viewport, viewport->Alpha);
16950 viewport->LastAlpha = viewport->Alpha;
16951
16952 // Optional, general purpose call to allow the backend to perform general book-keeping even if things haven't changed.
16955
16956 if (is_new_platform_window)
16957 {
16958 // On startup ensure new platform window don't steal focus (give it a few frames, as nested contents may lead to viewport being created a few frames late)
16959 if (g.FrameCount < 3)
16961
16962 // Show window
16963 g.PlatformIO.Platform_ShowWindow(viewport);
16964
16965 // Even without focus, we assume the window becomes front-most.
16966 // This is useful for our platform z-order heuristic when io.MouseHoveredViewport is not available.
16969 }
16970
16971 // Clear request flags
16972 viewport->ClearRequestFlags();
16973 }
16974}
16975
16976// This is a default/basic function for performing the rendering/swap of multiple Platform Windows.
16977// Custom renderers may prefer to not call this function at all, and instead iterate the publicly exposed platform data and handle rendering/sync themselves.
16978// The Render/Swap functions stored in ImGuiPlatformIO are merely here to allow for this helper to exist, but you can do it yourself:
16979//
16980// ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
16981// for (int i = 1; i < platform_io.Viewports.Size; i++)
16982// if ((platform_io.Viewports[i]->Flags & ImGuiViewportFlags_Minimized) == 0)
16983// MyRenderFunction(platform_io.Viewports[i], my_args);
16984// for (int i = 1; i < platform_io.Viewports.Size; i++)
16985// if ((platform_io.Viewports[i]->Flags & ImGuiViewportFlags_Minimized) == 0)
16986// MySwapBufferFunction(platform_io.Viewports[i], my_args);
16987//
16988void ImGui::RenderPlatformWindowsDefault(void* platform_render_arg, void* renderer_render_arg)
16989{
16990 // Skip the main viewport (index 0), which is always fully handled by the application!
16991 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
16992 for (int i = 1; i < platform_io.Viewports.Size; i++)
16993 {
16994 ImGuiViewport* viewport = platform_io.Viewports[i];
16995 if (viewport->Flags & ImGuiViewportFlags_IsMinimized)
16996 continue;
16997 if (platform_io.Platform_RenderWindow) platform_io.Platform_RenderWindow(viewport, platform_render_arg);
16998 if (platform_io.Renderer_RenderWindow) platform_io.Renderer_RenderWindow(viewport, renderer_render_arg);
16999 }
17000 for (int i = 1; i < platform_io.Viewports.Size; i++)
17001 {
17002 ImGuiViewport* viewport = platform_io.Viewports[i];
17003 if (viewport->Flags & ImGuiViewportFlags_IsMinimized)
17004 continue;
17005 if (platform_io.Platform_SwapBuffers) platform_io.Platform_SwapBuffers(viewport, platform_render_arg);
17006 if (platform_io.Renderer_SwapBuffers) platform_io.Renderer_SwapBuffers(viewport, renderer_render_arg);
17007 }
17008}
17009
17011{
17012 ImGuiContext& g = *GImGui;
17013 for (int monitor_n = 0; monitor_n < g.PlatformIO.Monitors.Size; monitor_n++)
17014 {
17015 const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[monitor_n];
17016 if (ImRect(monitor.MainPos, monitor.MainPos + monitor.MainSize).Contains(pos))
17017 return monitor_n;
17018 }
17019 return -1;
17020}
17021
17022// Search for the monitor with the largest intersection area with the given rectangle
17023// We generally try to avoid searching loops but the monitor count should be very small here
17024// FIXME-OPT: We could test the last monitor used for that viewport first, and early
17026{
17027 ImGuiContext& g = *GImGui;
17028
17029 const int monitor_count = g.PlatformIO.Monitors.Size;
17030 if (monitor_count <= 1)
17031 return monitor_count - 1;
17032
17033 // Use a minimum threshold of 1.0f so a zero-sized rect won't false positive, and will still find the correct monitor given its position.
17034 // This is necessary for tooltips which always resize down to zero at first.
17035 const float surface_threshold = ImMax(rect.GetWidth() * rect.GetHeight() * 0.5f, 1.0f);
17036 int best_monitor_n = 0; // Default to the first monitor as fallback
17037 float best_monitor_surface = 0.001f;
17038
17039 for (int monitor_n = 0; monitor_n < g.PlatformIO.Monitors.Size && best_monitor_surface < surface_threshold; monitor_n++)
17040 {
17041 const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[monitor_n];
17042 const ImRect monitor_rect = ImRect(monitor.MainPos, monitor.MainPos + monitor.MainSize);
17043 if (monitor_rect.Contains(rect))
17044 return monitor_n;
17045 ImRect overlapping_rect = rect;
17046 overlapping_rect.ClipWithFull(monitor_rect);
17047 float overlapping_surface = overlapping_rect.GetWidth() * overlapping_rect.GetHeight();
17048 if (overlapping_surface < best_monitor_surface)
17049 continue;
17050 best_monitor_surface = overlapping_surface;
17051 best_monitor_n = monitor_n;
17052 }
17053 return best_monitor_n;
17054}
17055
17056// Update monitor from viewport rectangle (we'll use this info to clamp windows and save windows lost in a removed monitor)
17058{
17059 viewport->PlatformMonitor = (short)FindPlatformMonitorForRect(viewport->GetMainRect());
17060}
17061
17062// Return value is always != NULL, but don't hold on it across frames.
17064{
17065 ImGuiContext& g = *GImGui;
17066 ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)viewport_p;
17067 int monitor_idx = viewport->PlatformMonitor;
17068 if (monitor_idx >= 0 && monitor_idx < g.PlatformIO.Monitors.Size)
17069 return &g.PlatformIO.Monitors[monitor_idx];
17070 return &g.FallbackMonitor;
17071}
17072
17074{
17075 ImGuiContext& g = *GImGui;
17076 if (viewport->PlatformWindowCreated)
17077 {
17078 IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Destroy Platform Window %08X '%s'\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a");
17083 IM_ASSERT(viewport->RendererUserData == NULL && viewport->PlatformUserData == NULL);
17084
17085 // Don't clear PlatformWindowCreated for the main viewport, as we initially set that up to true in Initialize()
17086 // The righter way may be to leave it to the backend to set this flag all-together, and made the flag public.
17087 if (viewport->ID != IMGUI_VIEWPORT_DEFAULT_ID)
17088 viewport->PlatformWindowCreated = false;
17089 }
17090 else
17091 {
17092 IM_ASSERT(viewport->RendererUserData == NULL && viewport->PlatformUserData == NULL && viewport->PlatformHandle == NULL);
17093 }
17094 viewport->RendererUserData = viewport->PlatformUserData = viewport->PlatformHandle = NULL;
17095 viewport->ClearRequestFlags();
17096}
17097
17099{
17100 // We call the destroy window on every viewport (including the main viewport, index 0) to give a chance to the backend
17101 // to clear any data they may have stored in e.g. PlatformUserData, RendererUserData.
17102 // It is convenient for the platform backend code to store something in the main viewport, in order for e.g. the mouse handling
17103 // code to operator a consistent manner.
17104 // It is expected that the backend can handle calls to Renderer_DestroyWindow/Platform_DestroyWindow without
17105 // crashing if it doesn't have data stored.
17106 ImGuiContext& g = *GImGui;
17107 for (ImGuiViewportP* viewport : g.Viewports)
17108 DestroyPlatformWindow(viewport);
17109}
17110
17111
17112//-----------------------------------------------------------------------------
17113// [SECTION] DOCKING
17114//-----------------------------------------------------------------------------
17115// Docking: Internal Types
17116// Docking: Forward Declarations
17117// Docking: ImGuiDockContext
17118// Docking: ImGuiDockContext Docking/Undocking functions
17119// Docking: ImGuiDockNode
17120// Docking: ImGuiDockNode Tree manipulation functions
17121// Docking: Public Functions (SetWindowDock, DockSpace, DockSpaceOverViewport)
17122// Docking: Builder Functions
17123// Docking: Begin/End Support Functions (called from Begin/End)
17124// Docking: Settings
17125//-----------------------------------------------------------------------------
17126
17127//-----------------------------------------------------------------------------
17128// Typical Docking call flow: (root level is generally public API):
17129//-----------------------------------------------------------------------------
17130// - NewFrame() new dear imgui frame
17131// | DockContextNewFrameUpdateUndocking() - process queued undocking requests
17132// | - DockContextProcessUndockWindow() - process one window undocking request
17133// | - DockContextProcessUndockNode() - process one whole node undocking request
17134// | DockContextNewFrameUpdateUndocking() - process queue docking requests, create floating dock nodes
17135// | - update g.HoveredDockNode - [debug] update node hovered by mouse
17136// | - DockContextProcessDock() - process one docking request
17137// | - DockNodeUpdate()
17138// | - DockNodeUpdateForRootNode()
17139// | - DockNodeUpdateFlagsAndCollapse()
17140// | - DockNodeFindInfo()
17141// | - destroy unused node or tab bar
17142// | - create dock node host window
17143// | - Begin() etc.
17144// | - DockNodeStartMouseMovingWindow()
17145// | - DockNodeTreeUpdatePosSize()
17146// | - DockNodeTreeUpdateSplitter()
17147// | - draw node background
17148// | - DockNodeUpdateTabBar() - create/update tab bar for a docking node
17149// | - DockNodeAddTabBar()
17150// | - DockNodeWindowMenuUpdate()
17151// | - DockNodeCalcTabBarLayout()
17152// | - BeginTabBarEx()
17153// | - TabItemEx() calls
17154// | - EndTabBar()
17155// | - BeginDockableDragDropTarget()
17156// | - DockNodeUpdate() - recurse into child nodes...
17157//-----------------------------------------------------------------------------
17158// - DockSpace() user submit a dockspace into a window
17159// | Begin(Child) - create a child window
17160// | DockNodeUpdate() - call main dock node update function
17161// | End(Child)
17162// | ItemSize()
17163//-----------------------------------------------------------------------------
17164// - Begin()
17165// | BeginDocked()
17166// | BeginDockableDragDropSource()
17167// | BeginDockableDragDropTarget()
17168// | - DockNodePreviewDockRender()
17169//-----------------------------------------------------------------------------
17170// - EndFrame()
17171// | DockContextEndFrame()
17172//-----------------------------------------------------------------------------
17173
17174//-----------------------------------------------------------------------------
17175// Docking: Internal Types
17176//-----------------------------------------------------------------------------
17177// - ImGuiDockRequestType
17178// - ImGuiDockRequest
17179// - ImGuiDockPreviewData
17180// - ImGuiDockNodeSettings
17181// - ImGuiDockContext
17182//-----------------------------------------------------------------------------
17183
17185{
17189 ImGuiDockRequestType_Split // Split is the same as Dock but without a DockPayload
17191
17193{
17195 ImGuiWindow* DockTargetWindow; // Destination/Target Window to dock into (may be a loose window or a DockNode, might be NULL in which case DockTargetNode cannot be NULL)
17196 ImGuiDockNode* DockTargetNode; // Destination/Target Node to dock into
17197 ImGuiWindow* DockPayload; // Source/Payload window to dock (may be a loose window or a DockNode), [Optional]
17203
17205 {
17210 DockSplitRatio = 0.5f;
17211 DockSplitOuter = false;
17212 }
17213};
17214
17216{
17220 bool IsSidesAvailable; // Hold your breath, grammar freaks..
17221 bool IsSplitDirExplicit; // Set when hovered the drop rect (vs. implicit SplitDir==None when hovered the window)
17225 ImRect DropRectsDraw[ImGuiDir_COUNT + 1]; // May be slightly different from hit-testing drop rects used in DockNodeCalcDropRects()
17226
17227 ImGuiDockPreviewData() : FutureNode(0) { IsDropAllowed = IsCenterAvailable = IsSidesAvailable = IsSplitDirExplicit = false; SplitNode = NULL; SplitDir = ImGuiDir_None; SplitRatio = 0.f; for (int n = 0; n < IM_ARRAYSIZE(DropRectsDraw); n++) DropRectsDraw[n] = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX); }
17228};
17229
17230// Persistent Settings data, stored contiguously in SettingsNodes (sizeof() ~32 bytes)
17232{
17237 signed char SplitAxis;
17238 char Depth;
17239 ImGuiDockNodeFlags Flags; // NB: We save individual flags one by one in ascii format (ImGuiDockNodeFlags_SavedFlagsMask_)
17243 ImGuiDockNodeSettings() { memset(this, 0, sizeof(*this)); SplitAxis = ImGuiAxis_None; }
17244};
17245
17246//-----------------------------------------------------------------------------
17247// Docking: Forward Declarations
17248//-----------------------------------------------------------------------------
17249
17250namespace ImGui
17251{
17252 // ImGuiDockContext
17254 static void DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node, bool merge_sibling_into_parent_node);
17259 static void DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDockNodeSettings* node_settings_array, int node_settings_count);
17260 static void DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id); // Use root_id==0 to add all
17261
17262 // ImGuiDockNode
17263 static void DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar);
17264 static void DockNodeMoveWindows(ImGuiDockNode* dst_node, ImGuiDockNode* src_node);
17265 static void DockNodeMoveChildNodes(ImGuiDockNode* dst_node, ImGuiDockNode* src_node);
17268 static void DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window, ImGuiID save_dock_id);
17269 static void DockNodeHideHostWindow(ImGuiDockNode* node);
17270 static void DockNodeUpdate(ImGuiDockNode* node);
17271 static void DockNodeUpdateForRootNode(ImGuiDockNode* node);
17274 static void DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_window);
17275 static void DockNodeAddTabBar(ImGuiDockNode* node);
17276 static void DockNodeRemoveTabBar(ImGuiDockNode* node);
17277 static void DockNodeWindowMenuUpdate(ImGuiDockNode* node, ImGuiTabBar* tab_bar);
17278 static void DockNodeUpdateVisibleFlag(ImGuiDockNode* node);
17279 static void DockNodeStartMouseMovingWindow(ImGuiDockNode* node, ImGuiWindow* window);
17280 static bool DockNodeIsDropAllowed(ImGuiWindow* host_window, ImGuiWindow* payload_window);
17281 static void DockNodePreviewDockSetup(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, ImGuiDockNode* payload_node, ImGuiDockPreviewData* preview_data, bool is_explicit_target, bool is_outer_docking);
17282 static void DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, const ImGuiDockPreviewData* preview_data);
17283 static void DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_window_menu_button_pos, ImVec2* out_close_button_pos);
17284 static void DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& pos_new, ImVec2& size_new, ImGuiDir dir, ImVec2 size_new_desired);
17285 static bool DockNodeCalcDropRectsAndTestMousePos(const ImRect& parent, ImGuiDir dir, ImRect& out_draw, bool outer_docking, ImVec2* test_mouse_pos);
17286 static const char* DockNodeGetHostWindowTitle(ImGuiDockNode* node, char* buf, int buf_size) { ImFormatString(buf, buf_size, "##DockNode_%02X", node->ID); return buf; }
17287 static int DockNodeGetTabOrder(ImGuiWindow* window);
17288
17289 // ImGuiDockNode tree manipulations
17290 static void DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiAxis split_axis, int split_first_child, float split_ratio, ImGuiDockNode* new_node);
17291 static void DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiDockNode* merge_lead_child);
17292 static void DockNodeTreeUpdatePosSize(ImGuiDockNode* node, ImVec2 pos, ImVec2 size, ImGuiDockNode* only_write_to_single_node = NULL);
17293 static void DockNodeTreeUpdateSplitter(ImGuiDockNode* node);
17296
17297 // Settings
17298 static void DockSettingsRenameNodeReferences(ImGuiID old_node_id, ImGuiID new_node_id);
17299 static void DockSettingsRemoveNodeReferences(ImGuiID* node_ids, int node_ids_count);
17303 static void* DockSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
17304 static void DockSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
17305 static void DockSettingsHandler_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf);
17306}
17307
17308//-----------------------------------------------------------------------------
17309// Docking: ImGuiDockContext
17310//-----------------------------------------------------------------------------
17311// The lifetime model is different from the one of regular windows: we always create a ImGuiDockNode for each ImGuiDockNodeSettings,
17312// or we always hold the entire docking node tree. Nodes are frequently hidden, e.g. if the window(s) or child nodes they host are not active.
17313// At boot time only, we run a simple GC to remove nodes that have no references.
17314// Because dock node settings (which are small, contiguous structures) are always mirrored by their corresponding dock nodes (more complete structures),
17315// we can also very easily recreate the nodes from scratch given the settings data (this is what DockContextRebuild() does).
17316// This is convenient as docking reconfiguration can be implemented by mostly poking at the simpler settings data.
17317//-----------------------------------------------------------------------------
17318// - DockContextInitialize()
17319// - DockContextShutdown()
17320// - DockContextClearNodes()
17321// - DockContextRebuildNodes()
17322// - DockContextNewFrameUpdateUndocking()
17323// - DockContextNewFrameUpdateDocking()
17324// - DockContextEndFrame()
17325// - DockContextFindNodeByID()
17326// - DockContextBindNodeToWindow()
17327// - DockContextGenNodeID()
17328// - DockContextAddNode()
17329// - DockContextRemoveNode()
17330// - ImGuiDockContextPruneNodeData
17331// - DockContextPruneUnusedSettingsNodes()
17332// - DockContextBuildNodesFromSettings()
17333// - DockContextBuildAddWindowsToNodes()
17334//-----------------------------------------------------------------------------
17335
17337{
17338 ImGuiContext& g = *ctx;
17339
17340 // Add .ini handle for persistent docking data
17341 ImGuiSettingsHandler ini_handler;
17342 ini_handler.TypeName = "Docking";
17343 ini_handler.TypeHash = ImHashStr("Docking");
17345 ini_handler.ReadInitFn = DockSettingsHandler_ClearAll; // Also clear on read
17350 g.SettingsHandlers.push_back(ini_handler);
17351
17353}
17354
17356{
17357 ImGuiDockContext* dc = &ctx->DockContext;
17358 for (int n = 0; n < dc->Nodes.Data.Size; n++)
17359 if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
17360 IM_DELETE(node);
17361}
17362
17363void ImGui::DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear_settings_refs)
17364{
17365 IM_UNUSED(ctx);
17366 IM_ASSERT(ctx == GImGui);
17367 DockBuilderRemoveNodeDockedWindows(root_id, clear_settings_refs);
17369}
17370
17371// [DEBUG] This function also acts as a defacto test to make sure we can rebuild from scratch without a glitch
17372// (Different from DockSettingsHandler_ClearAll() + DockSettingsHandler_ApplyAll() because this reuses current settings!)
17374{
17375 ImGuiContext& g = *ctx;
17376 ImGuiDockContext* dc = &ctx->DockContext;
17377 IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextRebuildNodes\n");
17379 ImGuiID root_id = 0; // Rebuild all
17380 DockContextClearNodes(ctx, root_id, false);
17383}
17384
17385// Docking context update function, called by NewFrame()
17387{
17388 ImGuiContext& g = *ctx;
17389 ImGuiDockContext* dc = &ctx->DockContext;
17391 {
17392 if (dc->Nodes.Data.Size > 0 || dc->Requests.Size > 0)
17393 DockContextClearNodes(ctx, 0, true);
17394 return;
17395 }
17396
17397 // Setting NoSplit at runtime merges all nodes
17399 for (int n = 0; n < dc->Nodes.Data.Size; n++)
17400 if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
17401 if (node->IsRootNode() && node->IsSplitNode())
17402 {
17404 //dc->WantFullRebuild = true;
17405 }
17406
17407 // Process full rebuild
17408#if 0
17409 if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
17410 dc->WantFullRebuild = true;
17411#endif
17412 if (dc->WantFullRebuild)
17413 {
17415 dc->WantFullRebuild = false;
17416 }
17417
17418 // Process Undocking requests (we need to process them _before_ the UpdateMouseMovingWindowNewFrame call in NewFrame)
17419 for (ImGuiDockRequest& req : dc->Requests)
17420 {
17423 else if (req.Type == ImGuiDockRequestType_Undock && req.UndockTargetNode)
17425 }
17426}
17427
17428// Docking context update function, called by NewFrame()
17430{
17431 ImGuiContext& g = *ctx;
17432 ImGuiDockContext* dc = &ctx->DockContext;
17434 return;
17435
17436 // [DEBUG] Store hovered dock node.
17437 // We could in theory use DockNodeTreeFindVisibleNodeByPos() on the root host dock node, but using ->DockNode is a good shortcut.
17438 // Note this is mostly a debug thing and isn't actually used for docking target, because docking involve more detailed filtering.
17439 g.DebugHoveredDockNode = NULL;
17440 if (ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow)
17441 {
17442 if (hovered_window->DockNodeAsHost)
17443 g.DebugHoveredDockNode = DockNodeTreeFindVisibleNodeByPos(hovered_window->DockNodeAsHost, g.IO.MousePos);
17444 else if (hovered_window->RootWindow->DockNode)
17445 g.DebugHoveredDockNode = hovered_window->RootWindow->DockNode;
17446 }
17447
17448 // Process Docking requests
17449 for (ImGuiDockRequest& req : dc->Requests)
17451 DockContextProcessDock(ctx, &req);
17452 dc->Requests.resize(0);
17453
17454 // Create windows for each automatic docking nodes
17455 // We can have NULL pointers when we delete nodes, but because ID are recycled this should amortize nicely (and our node count will never be very high)
17456 for (int n = 0; n < dc->Nodes.Data.Size; n++)
17457 if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
17458 if (node->IsFloatingNode())
17459 DockNodeUpdate(node);
17460}
17461
17463{
17464 // Draw backgrounds of node missing their window
17465 ImGuiContext& g = *ctx;
17467 for (int n = 0; n < dc->Nodes.Data.Size; n++)
17468 if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
17469 if (node->LastFrameActive == g.FrameCount && node->IsVisible && node->HostWindow && node->IsLeafNode() && !node->IsBgDrawnThisFrame)
17470 {
17471 ImRect bg_rect(node->Pos + ImVec2(0.0f, GetFrameHeight()), node->Pos + node->Size);
17472 ImDrawFlags bg_rounding_flags = CalcRoundingFlagsForRectInRect(bg_rect, node->HostWindow->Rect(), g.Style.DockingSeparatorSize);
17473 node->HostWindow->DrawList->ChannelsSetCurrent(DOCKING_HOST_DRAW_CHANNEL_BG);
17474 node->HostWindow->DrawList->AddRectFilled(bg_rect.Min, bg_rect.Max, node->LastBgColor, node->HostWindow->WindowRounding, bg_rounding_flags);
17475 }
17476}
17477
17479{
17480 return (ImGuiDockNode*)ctx->DockContext.Nodes.GetVoidPtr(id);
17481}
17482
17484{
17485 // Generate an ID for new node (the exact ID value doesn't matter as long as it is not already used)
17486 // FIXME-OPT FIXME-DOCK: This is suboptimal, even if the node count is small enough not to be a worry.0
17487 // We should poke in ctx->Nodes to find a suitable ID faster. Even more so trivial that ctx->Nodes lookup is already sorted.
17488 ImGuiID id = 0x0001;
17489 while (DockContextFindNodeByID(ctx, id) != NULL)
17490 id++;
17491 return id;
17492}
17493
17495{
17496 // Generate an ID for the new node (the exact ID value doesn't matter as long as it is not already used) and add the first window.
17497 ImGuiContext& g = *ctx;
17498 if (id == 0)
17499 id = DockContextGenNodeID(ctx);
17500 else
17501 IM_ASSERT(DockContextFindNodeByID(ctx, id) == NULL);
17502
17503 // We don't set node->LastFrameAlive on construction. Nodes are always created at all time to reflect .ini settings!
17504 IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextAddNode 0x%08X\n", id);
17505 ImGuiDockNode* node = IM_NEW(ImGuiDockNode)(id);
17506 ctx->DockContext.Nodes.SetVoidPtr(node->ID, node);
17507 return node;
17508}
17509
17510static void ImGui::DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node, bool merge_sibling_into_parent_node)
17511{
17512 ImGuiContext& g = *ctx;
17513 ImGuiDockContext* dc = &ctx->DockContext;
17514
17515 IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextRemoveNode 0x%08X\n", node->ID);
17516 IM_ASSERT(DockContextFindNodeByID(ctx, node->ID) == node);
17517 IM_ASSERT(node->ChildNodes[0] == NULL && node->ChildNodes[1] == NULL);
17518 IM_ASSERT(node->Windows.Size == 0);
17519
17520 if (node->HostWindow)
17521 node->HostWindow->DockNodeAsHost = NULL;
17522
17523 ImGuiDockNode* parent_node = node->ParentNode;
17524 const bool merge = (merge_sibling_into_parent_node && parent_node != NULL);
17525 if (merge)
17526 {
17527 IM_ASSERT(parent_node->ChildNodes[0] == node || parent_node->ChildNodes[1] == node);
17528 ImGuiDockNode* sibling_node = (parent_node->ChildNodes[0] == node ? parent_node->ChildNodes[1] : parent_node->ChildNodes[0]);
17529 DockNodeTreeMerge(&g, parent_node, sibling_node);
17530 }
17531 else
17532 {
17533 for (int n = 0; parent_node && n < IM_ARRAYSIZE(parent_node->ChildNodes); n++)
17534 if (parent_node->ChildNodes[n] == node)
17535 node->ParentNode->ChildNodes[n] = NULL;
17536 dc->Nodes.SetVoidPtr(node->ID, NULL);
17537 IM_DELETE(node);
17538 }
17539}
17540
17541static int IMGUI_CDECL DockNodeComparerDepthMostFirst(const void* lhs, const void* rhs)
17542{
17543 const ImGuiDockNode* a = *(const ImGuiDockNode* const*)lhs;
17544 const ImGuiDockNode* b = *(const ImGuiDockNode* const*)rhs;
17546}
17547
17548// Pre C++0x doesn't allow us to use a function-local type (without linkage) as template parameter, so we moved this here.
17550{
17554};
17555
17556// Garbage collect unused nodes (run once at init time)
17558{
17559 ImGuiContext& g = *ctx;
17560 ImGuiDockContext* dc = &ctx->DockContext;
17561 IM_ASSERT(g.Windows.Size == 0);
17562
17564 pool.Reserve(dc->NodesSettings.Size);
17565
17566 // Count child nodes and compute RootID
17567 for (int settings_n = 0; settings_n < dc->NodesSettings.Size; settings_n++)
17568 {
17569 ImGuiDockNodeSettings* settings = &dc->NodesSettings[settings_n];
17570 ImGuiDockContextPruneNodeData* parent_data = settings->ParentNodeId ? pool.GetByKey(settings->ParentNodeId) : 0;
17571 pool.GetOrAddByKey(settings->ID)->RootId = parent_data ? parent_data->RootId : settings->ID;
17572 if (settings->ParentNodeId)
17573 pool.GetOrAddByKey(settings->ParentNodeId)->CountChildNodes++;
17574 }
17575
17576 // Count reference to dock ids from dockspaces
17577 // We track the 'auto-DockNode <- manual-Window <- manual-DockSpace' in order to avoid 'auto-DockNode' being ditched by DockContextPruneUnusedSettingsNodes()
17578 for (int settings_n = 0; settings_n < dc->NodesSettings.Size; settings_n++)
17579 {
17580 ImGuiDockNodeSettings* settings = &dc->NodesSettings[settings_n];
17581 if (settings->ParentWindowId != 0)
17582 if (ImGuiWindowSettings* window_settings = FindWindowSettingsByID(settings->ParentWindowId))
17583 if (window_settings->DockId)
17584 if (ImGuiDockContextPruneNodeData* data = pool.GetByKey(window_settings->DockId))
17585 data->CountChildNodes++;
17586 }
17587
17588 // Count reference to dock ids from window settings
17589 // We guard against the possibility of an invalid .ini file (RootID may point to a missing node)
17590 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
17591 if (ImGuiID dock_id = settings->DockId)
17592 if (ImGuiDockContextPruneNodeData* data = pool.GetByKey(dock_id))
17593 {
17594 data->CountWindows++;
17595 if (ImGuiDockContextPruneNodeData* data_root = (data->RootId == dock_id) ? data : pool.GetByKey(data->RootId))
17596 data_root->CountChildWindows++;
17597 }
17598
17599 // Prune
17600 for (int settings_n = 0; settings_n < dc->NodesSettings.Size; settings_n++)
17601 {
17602 ImGuiDockNodeSettings* settings = &dc->NodesSettings[settings_n];
17603 ImGuiDockContextPruneNodeData* data = pool.GetByKey(settings->ID);
17604 if (data == NULL || data->CountWindows > 1)
17605 continue;
17606 ImGuiDockContextPruneNodeData* data_root = (data->RootId == settings->ID) ? data : pool.GetByKey(data->RootId);
17607
17608 bool remove = false;
17609 remove |= (data->CountWindows == 1 && settings->ParentNodeId == 0 && data->CountChildNodes == 0 && !(settings->Flags & ImGuiDockNodeFlags_CentralNode)); // Floating root node with only 1 window
17610 remove |= (data->CountWindows == 0 && settings->ParentNodeId == 0 && data->CountChildNodes == 0); // Leaf nodes with 0 window
17611 remove |= (data_root->CountChildWindows == 0);
17612 if (remove)
17613 {
17614 IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextPruneUnusedSettingsNodes: Prune 0x%08X\n", settings->ID);
17615 DockSettingsRemoveNodeReferences(&settings->ID, 1);
17616 settings->ID = 0;
17617 }
17618 }
17619}
17620
17621static void ImGui::DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDockNodeSettings* node_settings_array, int node_settings_count)
17622{
17623 // Build nodes
17624 for (int node_n = 0; node_n < node_settings_count; node_n++)
17625 {
17626 ImGuiDockNodeSettings* settings = &node_settings_array[node_n];
17627 if (settings->ID == 0)
17628 continue;
17629 ImGuiDockNode* node = DockContextAddNode(ctx, settings->ID);
17630 node->ParentNode = settings->ParentNodeId ? DockContextFindNodeByID(ctx, settings->ParentNodeId) : NULL;
17631 node->Pos = ImVec2(settings->Pos.x, settings->Pos.y);
17632 node->Size = ImVec2(settings->Size.x, settings->Size.y);
17633 node->SizeRef = ImVec2(settings->SizeRef.x, settings->SizeRef.y);
17635 if (node->ParentNode && node->ParentNode->ChildNodes[0] == NULL)
17636 node->ParentNode->ChildNodes[0] = node;
17637 else if (node->ParentNode && node->ParentNode->ChildNodes[1] == NULL)
17638 node->ParentNode->ChildNodes[1] = node;
17639 node->SelectedTabId = settings->SelectedTabId;
17640 node->SplitAxis = (ImGuiAxis)settings->SplitAxis;
17642
17643 // Bind host window immediately if it already exist (in case of a rebuild)
17644 // This is useful as the RootWindowForTitleBarHighlight links necessary to highlight the currently focused node requires node->HostWindow to be set.
17645 char host_window_title[20];
17646 ImGuiDockNode* root_node = DockNodeGetRootNode(node);
17647 node->HostWindow = FindWindowByName(DockNodeGetHostWindowTitle(root_node, host_window_title, IM_ARRAYSIZE(host_window_title)));
17648 }
17649}
17650
17652{
17653 // Rebind all windows to nodes (they can also lazily rebind but we'll have a visible glitch during the first frame)
17654 ImGuiContext& g = *ctx;
17655 for (ImGuiWindow* window : g.Windows)
17656 {
17657 if (window->DockId == 0 || window->LastFrameActive < g.FrameCount - 1)
17658 continue;
17659 if (window->DockNode != NULL)
17660 continue;
17661
17662 ImGuiDockNode* node = DockContextFindNodeByID(ctx, window->DockId);
17663 IM_ASSERT(node != NULL); // This should have been called after DockContextBuildNodesFromSettings()
17664 if (root_id == 0 || DockNodeGetRootNode(node)->ID == root_id)
17665 DockNodeAddWindow(node, window, true);
17666 }
17667}
17668
17669//-----------------------------------------------------------------------------
17670// Docking: ImGuiDockContext Docking/Undocking functions
17671//-----------------------------------------------------------------------------
17672// - DockContextQueueDock()
17673// - DockContextQueueUndockWindow()
17674// - DockContextQueueUndockNode()
17675// - DockContextQueueNotifyRemovedNode()
17676// - DockContextProcessDock()
17677// - DockContextProcessUndockWindow()
17678// - DockContextProcessUndockNode()
17679// - DockContextCalcDropPosForDocking()
17680//-----------------------------------------------------------------------------
17681
17682void ImGui::DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer)
17683{
17684 IM_ASSERT(target != payload);
17685 ImGuiDockRequest req;
17687 req.DockTargetWindow = target;
17688 req.DockTargetNode = target_node;
17689 req.DockPayload = payload;
17690 req.DockSplitDir = split_dir;
17691 req.DockSplitRatio = split_ratio;
17692 req.DockSplitOuter = split_outer;
17693 ctx->DockContext.Requests.push_back(req);
17694}
17695
17697{
17698 ImGuiDockRequest req;
17700 req.UndockTargetWindow = window;
17701 ctx->DockContext.Requests.push_back(req);
17702}
17703
17705{
17706 ImGuiDockRequest req;
17708 req.UndockTargetNode = node;
17709 ctx->DockContext.Requests.push_back(req);
17710}
17711
17713{
17714 ImGuiDockContext* dc = &ctx->DockContext;
17715 for (ImGuiDockRequest& req : dc->Requests)
17716 if (req.DockTargetNode == node)
17718}
17719
17721{
17722 IM_ASSERT((req->Type == ImGuiDockRequestType_Dock && req->DockPayload != NULL) || (req->Type == ImGuiDockRequestType_Split && req->DockPayload == NULL));
17723 IM_ASSERT(req->DockTargetWindow != NULL || req->DockTargetNode != NULL);
17724
17725 ImGuiContext& g = *ctx;
17726 IM_UNUSED(g);
17727
17728 ImGuiWindow* payload_window = req->DockPayload; // Optional
17729 ImGuiWindow* target_window = req->DockTargetWindow;
17730 ImGuiDockNode* node = req->DockTargetNode;
17731 if (payload_window)
17732 IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextProcessDock node 0x%08X target '%s' dock window '%s', split_dir %d\n", node ? node->ID : 0, target_window ? target_window->Name : "NULL", payload_window->Name, req->DockSplitDir);
17733 else
17734 IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextProcessDock node 0x%08X, split_dir %d\n", node ? node->ID : 0, req->DockSplitDir);
17735
17736 // Decide which Tab will be selected at the end of the operation
17737 ImGuiID next_selected_id = 0;
17738 ImGuiDockNode* payload_node = NULL;
17739 if (payload_window)
17740 {
17741 payload_node = payload_window->DockNodeAsHost;
17742 payload_window->DockNodeAsHost = NULL; // Important to clear this as the node will have its life as a child which might be merged/deleted later.
17743 if (payload_node && payload_node->IsLeafNode())
17744 next_selected_id = payload_node->TabBar->NextSelectedTabId ? payload_node->TabBar->NextSelectedTabId : payload_node->TabBar->SelectedTabId;
17745 if (payload_node == NULL)
17746 next_selected_id = payload_window->TabId;
17747 }
17748
17749 // FIXME-DOCK: When we are trying to dock an existing single-window node into a loose window, transfer Node ID as well
17750 // When processing an interactive split, usually LastFrameAlive will be < g.FrameCount. But DockBuilder operations can make it ==.
17751 if (node)
17753 if (node && target_window && node == target_window->DockNodeAsHost)
17754 IM_ASSERT(node->Windows.Size > 0 || node->IsSplitNode() || node->IsCentralNode());
17755
17756 // Create new node and add existing window to it
17757 if (node == NULL)
17758 {
17759 node = DockContextAddNode(ctx, 0);
17760 node->Pos = target_window->Pos;
17761 node->Size = target_window->Size;
17762 if (target_window->DockNodeAsHost == NULL)
17763 {
17764 DockNodeAddWindow(node, target_window, true);
17765 node->TabBar->Tabs[0].Flags &= ~ImGuiTabItemFlags_Unsorted;
17766 target_window->DockIsActive = true;
17767 }
17768 }
17769
17770 ImGuiDir split_dir = req->DockSplitDir;
17771 if (split_dir != ImGuiDir_None)
17772 {
17773 // Split into two, one side will be our payload node unless we are dropping a loose window
17774 const ImGuiAxis split_axis = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y;
17775 const int split_inheritor_child_idx = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 1 : 0; // Current contents will be moved to the opposite side
17776 const float split_ratio = req->DockSplitRatio;
17777 DockNodeTreeSplit(ctx, node, split_axis, split_inheritor_child_idx, split_ratio, payload_node); // payload_node may be NULL here!
17778 ImGuiDockNode* new_node = node->ChildNodes[split_inheritor_child_idx ^ 1];
17779 new_node->HostWindow = node->HostWindow;
17780 node = new_node;
17781 }
17783
17784 if (node != payload_node)
17785 {
17786 // Create tab bar before we call DockNodeMoveWindows (which would attempt to move the old tab-bar, which would lead us to payload tabs wrongly appearing before target tabs!)
17787 if (node->Windows.Size > 0 && node->TabBar == NULL)
17788 {
17789 DockNodeAddTabBar(node);
17790 for (int n = 0; n < node->Windows.Size; n++)
17792 }
17793
17794 if (payload_node != NULL)
17795 {
17796 // Transfer full payload node (with 1+ child windows or child nodes)
17797 if (payload_node->IsSplitNode())
17798 {
17799 if (node->Windows.Size > 0)
17800 {
17801 // We can dock a split payload into a node that already has windows _only_ if our payload is a node tree with a single visible node.
17802 // In this situation, we move the windows of the target node into the currently visible node of the payload.
17803 // This allows us to preserve some of the underlying dock tree settings nicely.
17804 IM_ASSERT(payload_node->OnlyNodeWithWindows != NULL); // The docking should have been blocked by DockNodePreviewDockSetup() early on and never submitted.
17805 ImGuiDockNode* visible_node = payload_node->OnlyNodeWithWindows;
17806 if (visible_node->TabBar)
17807 IM_ASSERT(visible_node->TabBar->Tabs.Size > 0);
17808 DockNodeMoveWindows(node, visible_node);
17809 DockNodeMoveWindows(visible_node, node);
17810 DockSettingsRenameNodeReferences(node->ID, visible_node->ID);
17811 }
17812 if (node->IsCentralNode())
17813 {
17814 // Central node property needs to be moved to a leaf node, pick the last focused one.
17815 // FIXME-DOCK: If we had to transfer other flags here, what would the policy be?
17816 ImGuiDockNode* last_focused_node = DockContextFindNodeByID(ctx, payload_node->LastFocusedNodeId);
17817 IM_ASSERT(last_focused_node != NULL);
17818 ImGuiDockNode* last_focused_root_node = DockNodeGetRootNode(last_focused_node);
17819 IM_ASSERT(last_focused_root_node == DockNodeGetRootNode(payload_node));
17820 last_focused_node->SetLocalFlags(last_focused_node->LocalFlags | ImGuiDockNodeFlags_CentralNode);
17822 last_focused_root_node->CentralNode = last_focused_node;
17823 }
17824
17825 IM_ASSERT(node->Windows.Size == 0);
17826 DockNodeMoveChildNodes(node, payload_node);
17827 }
17828 else
17829 {
17830 const ImGuiID payload_dock_id = payload_node->ID;
17831 DockNodeMoveWindows(node, payload_node);
17832 DockSettingsRenameNodeReferences(payload_dock_id, node->ID);
17833 }
17834 DockContextRemoveNode(ctx, payload_node, true);
17835 }
17836 else if (payload_window)
17837 {
17838 // Transfer single window
17839 const ImGuiID payload_dock_id = payload_window->DockId;
17840 node->VisibleWindow = payload_window;
17841 DockNodeAddWindow(node, payload_window, true);
17842 if (payload_dock_id != 0)
17843 DockSettingsRenameNodeReferences(payload_dock_id, node->ID);
17844 }
17845 }
17846 else
17847 {
17848 // When docking a floating single window node we want to reevaluate auto-hiding of the tab bar
17849 node->WantHiddenTabBarUpdate = true;
17850 }
17851
17852 // Update selection immediately
17853 if (ImGuiTabBar* tab_bar = node->TabBar)
17854 tab_bar->NextSelectedTabId = next_selected_id;
17856}
17857
17858// Problem:
17859// Undocking a large (~full screen) window would leave it so large that the bottom right sizing corner would more
17860// than likely be off the screen and the window would be hard to resize to fit on screen. This can be particularly problematic
17861// with 'ConfigWindowsMoveFromTitleBarOnly=true' and/or with 'ConfigWindowsResizeFromEdges=false' as well (the later can be
17862// due to missing ImGuiBackendFlags_HasMouseCursors backend flag).
17863// Solution:
17864// When undocking a window we currently force its maximum size to 90% of the host viewport or monitor.
17865// Reevaluate this when we implement preserving docked/undocked size ("docking_wip/undocked_size" branch).
17867{
17868 if (ref_viewport == NULL)
17869 return size;
17870
17871 ImGuiContext& g = *GImGui;
17872 ImVec2 max_size = ImTrunc(ref_viewport->WorkSize * 0.90f);
17874 {
17875 const ImGuiPlatformMonitor* monitor = ImGui::GetViewportPlatformMonitor(ref_viewport);
17876 max_size = ImTrunc(monitor->WorkSize * 0.90f);
17877 }
17878 return ImMin(size, max_size);
17879}
17880
17881void ImGui::DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* window, bool clear_persistent_docking_ref)
17882{
17883 ImGuiContext& g = *ctx;
17884 IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextProcessUndockWindow window '%s', clear_persistent_docking_ref = %d\n", window->Name, clear_persistent_docking_ref);
17885 if (window->DockNode)
17886 DockNodeRemoveWindow(window->DockNode, window, clear_persistent_docking_ref ? 0 : window->DockId);
17887 else
17888 window->DockId = 0;
17889 window->Collapsed = false;
17890 window->DockIsActive = false;
17891 window->DockNodeIsVisible = window->DockTabIsVisible = false;
17892 window->Size = window->SizeFull = FixLargeWindowsWhenUndocking(window->SizeFull, window->Viewport);
17893
17895}
17896
17898{
17899 ImGuiContext& g = *ctx;
17900 IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextProcessUndockNode node %08X\n", node->ID);
17901 IM_ASSERT(node->IsLeafNode());
17902 IM_ASSERT(node->Windows.Size >= 1);
17903
17904 if (node->IsRootNode() || node->IsCentralNode())
17905 {
17906 // In the case of a root node or central node, the node will have to stay in place. Create a new node to receive the payload.
17907 ImGuiDockNode* new_node = DockContextAddNode(ctx, 0);
17908 new_node->Pos = node->Pos;
17909 new_node->Size = node->Size;
17910 new_node->SizeRef = node->SizeRef;
17911 DockNodeMoveWindows(new_node, node);
17912 DockSettingsRenameNodeReferences(node->ID, new_node->ID);
17913 node = new_node;
17914 }
17915 else
17916 {
17917 // Otherwise extract our node and merge our sibling back into the parent node.
17918 IM_ASSERT(node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node);
17919 int index_in_parent = (node->ParentNode->ChildNodes[0] == node) ? 0 : 1;
17920 node->ParentNode->ChildNodes[index_in_parent] = NULL;
17921 DockNodeTreeMerge(ctx, node->ParentNode, node->ParentNode->ChildNodes[index_in_parent ^ 1]);
17922 node->ParentNode->AuthorityForViewport = ImGuiDataAuthority_Window; // The node that stays in place keeps the viewport, so our newly dragged out node will create a new viewport
17923 node->ParentNode = NULL;
17924 }
17925 for (ImGuiWindow* window : node->Windows)
17926 {
17927 window->Flags &= ~ImGuiWindowFlags_ChildWindow;
17928 if (window->ParentWindow)
17929 window->ParentWindow->DC.ChildWindows.find_erase(window);
17930 UpdateWindowParentAndRootLinks(window, window->Flags, NULL);
17931 }
17933 node->Size = FixLargeWindowsWhenUndocking(node->Size, node->Windows[0]->Viewport);
17934 node->WantMouseMove = true;
17936}
17937
17938// This is mostly used for automation.
17939bool ImGui::DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload_window, ImGuiDockNode* payload_node, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos)
17940{
17941 if (target != NULL && target_node == NULL)
17942 target_node = target->DockNode;
17943
17944 // In DockNodePreviewDockSetup() for a root central node instead of showing both "inner" and "outer" drop rects
17945 // (which would be functionally identical) we only show the outer one. Reflect this here.
17946 if (target_node && target_node->ParentNode == NULL && target_node->IsCentralNode() && split_dir != ImGuiDir_None)
17947 split_outer = true;
17948 ImGuiDockPreviewData split_data;
17949 DockNodePreviewDockSetup(target, target_node, payload_window, payload_node, &split_data, false, split_outer);
17950 if (split_data.DropRectsDraw[split_dir+1].IsInverted())
17951 return false;
17952 *out_pos = split_data.DropRectsDraw[split_dir+1].GetCenter();
17953 return true;
17954}
17955
17956//-----------------------------------------------------------------------------
17957// Docking: ImGuiDockNode
17958//-----------------------------------------------------------------------------
17959// - DockNodeGetTabOrder()
17960// - DockNodeAddWindow()
17961// - DockNodeRemoveWindow()
17962// - DockNodeMoveChildNodes()
17963// - DockNodeMoveWindows()
17964// - DockNodeApplyPosSizeToWindows()
17965// - DockNodeHideHostWindow()
17966// - ImGuiDockNodeFindInfoResults
17967// - DockNodeFindInfo()
17968// - DockNodeFindWindowByID()
17969// - DockNodeUpdateFlagsAndCollapse()
17970// - DockNodeUpdateHasCentralNodeFlag()
17971// - DockNodeUpdateVisibleFlag()
17972// - DockNodeStartMouseMovingWindow()
17973// - DockNodeUpdate()
17974// - DockNodeUpdateWindowMenu()
17975// - DockNodeBeginAmendTabBar()
17976// - DockNodeEndAmendTabBar()
17977// - DockNodeUpdateTabBar()
17978// - DockNodeAddTabBar()
17979// - DockNodeRemoveTabBar()
17980// - DockNodeIsDropAllowedOne()
17981// - DockNodeIsDropAllowed()
17982// - DockNodeCalcTabBarLayout()
17983// - DockNodeCalcSplitRects()
17984// - DockNodeCalcDropRectsAndTestMousePos()
17985// - DockNodePreviewDockSetup()
17986// - DockNodePreviewDockRender()
17987//-----------------------------------------------------------------------------
17988
17990{
17991 ID = id;
17993 ParentNode = ChildNodes[0] = ChildNodes[1] = NULL;
17994 TabBar = NULL;
17996
17999 HostWindow = VisibleWindow = NULL;
18004 SelectedTabId = 0;
18005 WantCloseTabId = 0;
18006 RefViewportId = 0;
18009 IsVisible = true;
18011 IsBgDrawnThisFrame = false;
18013}
18014
18016{
18018 TabBar = NULL;
18019 ChildNodes[0] = ChildNodes[1] = NULL;
18020}
18021
18023{
18024 ImGuiTabBar* tab_bar = window->DockNode->TabBar;
18025 if (tab_bar == NULL)
18026 return -1;
18027 ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, window->TabId);
18028 return tab ? TabBarGetTabOrder(tab_bar, tab) : -1;
18029}
18030
18032{
18033 window->Hidden = true;
18034 window->HiddenFramesCanSkipItems = window->Active ? 1 : 2;
18035}
18036
18037static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar)
18038{
18039 ImGuiContext& g = *GImGui; (void)g;
18040 if (window->DockNode)
18041 {
18042 // Can overwrite an existing window->DockNode (e.g. pointing to a disabled DockSpace node)
18043 IM_ASSERT(window->DockNode->ID != node->ID);
18044 DockNodeRemoveWindow(window->DockNode, window, 0);
18045 }
18046 IM_ASSERT(window->DockNode == NULL || window->DockNodeAsHost == NULL);
18047 IMGUI_DEBUG_LOG_DOCKING("[docking] DockNodeAddWindow node 0x%08X window '%s'\n", node->ID, window->Name);
18048
18049 // If more than 2 windows appeared on the same frame leading to the creation of a new hosting window,
18050 // we'll hide windows until the host window is ready. Hide the 1st window after its been output (so it is not visible for one frame).
18051 // We will call DockNodeHideWindowDuringHostWindowCreation() on ourselves in Begin()
18052 if (node->HostWindow == NULL && node->Windows.Size == 1 && node->Windows[0]->WasActive == false)
18054
18055 node->Windows.push_back(window);
18056 node->WantHiddenTabBarUpdate = true;
18057 window->DockNode = node;
18058 window->DockId = node->ID;
18059 window->DockIsActive = (node->Windows.Size > 1);
18060 window->DockTabWantClose = false;
18061
18062 // When reactivating a node with one or two loose window, the window pos/size/viewport are authoritative over the node storage.
18063 // In particular it is important we init the viewport from the first window so we don't create two viewports and drop one.
18064 if (node->HostWindow == NULL && node->IsFloatingNode())
18065 {
18072 }
18073
18074 // Add to tab bar if requested
18075 if (add_to_tab_bar)
18076 {
18077 if (node->TabBar == NULL)
18078 {
18079 DockNodeAddTabBar(node);
18081
18082 // Add existing windows
18083 for (int n = 0; n < node->Windows.Size - 1; n++)
18085 }
18087 }
18088
18090
18091 // Update this without waiting for the next time we Begin() in the window, so our host window will have the proper title bar color on its first frame.
18092 if (node->HostWindow)
18094}
18095
18096static void ImGui::DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window, ImGuiID save_dock_id)
18097{
18098 ImGuiContext& g = *GImGui;
18099 IM_ASSERT(window->DockNode == node);
18100 //IM_ASSERT(window->RootWindowDockTree == node->HostWindow);
18101 //IM_ASSERT(window->LastFrameActive < g.FrameCount); // We may call this from Begin()
18102 IM_ASSERT(save_dock_id == 0 || save_dock_id == node->ID);
18103 IMGUI_DEBUG_LOG_DOCKING("[docking] DockNodeRemoveWindow node 0x%08X window '%s'\n", node->ID, window->Name);
18104
18105 window->DockNode = NULL;
18106 window->DockIsActive = window->DockTabWantClose = false;
18107 window->DockId = save_dock_id;
18108 window->Flags &= ~ImGuiWindowFlags_ChildWindow;
18109 if (window->ParentWindow)
18110 window->ParentWindow->DC.ChildWindows.find_erase(window);
18111 UpdateWindowParentAndRootLinks(window, window->Flags, NULL); // Update immediately
18112
18113 if (node->HostWindow && node->HostWindow->ViewportOwned)
18114 {
18115 // When undocking from a user interaction this will always run in NewFrame() and have not much effect.
18116 // But mid-frame, if we clear viewport we need to mark window as hidden as well.
18117 window->Viewport = NULL;
18118 window->ViewportId = 0;
18119 window->ViewportOwned = false;
18120 window->Hidden = true;
18121 }
18122
18123 // Remove window
18124 bool erased = false;
18125 for (int n = 0; n < node->Windows.Size; n++)
18126 if (node->Windows[n] == window)
18127 {
18128 node->Windows.erase(node->Windows.Data + n);
18129 erased = true;
18130 break;
18131 }
18132 if (!erased)
18133 IM_ASSERT(erased);
18134 if (node->VisibleWindow == window)
18135 node->VisibleWindow = NULL;
18136
18137 // Remove tab and possibly tab bar
18138 node->WantHiddenTabBarUpdate = true;
18139 if (node->TabBar)
18140 {
18141 TabBarRemoveTab(node->TabBar, window->TabId);
18142 const int tab_count_threshold_for_tab_bar = node->IsCentralNode() ? 1 : 2;
18143 if (node->Windows.Size < tab_count_threshold_for_tab_bar)
18145 }
18146
18147 if (node->Windows.Size == 0 && !node->IsCentralNode() && !node->IsDockSpace() && window->DockId != node->ID)
18148 {
18149 // Automatic dock node delete themselves if they are not holding at least one tab
18150 DockContextRemoveNode(&g, node, true);
18151 return;
18152 }
18153
18154 if (node->Windows.Size == 1 && !node->IsCentralNode() && node->HostWindow)
18155 {
18156 ImGuiWindow* remaining_window = node->Windows[0];
18157 // Note: we used to transport viewport ownership here.
18158 remaining_window->Collapsed = node->HostWindow->Collapsed;
18159 }
18160
18161 // Update visibility immediately is required so the DockNodeUpdateRemoveInactiveChilds() processing can reflect changes up the tree
18163}
18164
18166{
18167 IM_ASSERT(dst_node->Windows.Size == 0);
18168 dst_node->ChildNodes[0] = src_node->ChildNodes[0];
18169 dst_node->ChildNodes[1] = src_node->ChildNodes[1];
18170 if (dst_node->ChildNodes[0])
18171 dst_node->ChildNodes[0]->ParentNode = dst_node;
18172 if (dst_node->ChildNodes[1])
18173 dst_node->ChildNodes[1]->ParentNode = dst_node;
18174 dst_node->SplitAxis = src_node->SplitAxis;
18175 dst_node->SizeRef = src_node->SizeRef;
18176 src_node->ChildNodes[0] = src_node->ChildNodes[1] = NULL;
18177}
18178
18180{
18181 // Insert tabs in the same orders as currently ordered (node->Windows isn't ordered)
18182 IM_ASSERT(src_node && dst_node && dst_node != src_node);
18183 ImGuiTabBar* src_tab_bar = src_node->TabBar;
18184 if (src_tab_bar != NULL)
18185 IM_ASSERT(src_node->Windows.Size <= src_node->TabBar->Tabs.Size);
18186
18187 // If the dst_node is empty we can just move the entire tab bar (to preserve selection, scrolling, etc.)
18188 bool move_tab_bar = (src_tab_bar != NULL) && (dst_node->TabBar == NULL);
18189 if (move_tab_bar)
18190 {
18191 dst_node->TabBar = src_node->TabBar;
18192 src_node->TabBar = NULL;
18193 }
18194
18195 // Tab order is not important here, it is preserved by sorting in DockNodeUpdateTabBar().
18196 for (ImGuiWindow* window : src_node->Windows)
18197 {
18198 window->DockNode = NULL;
18199 window->DockIsActive = false;
18200 DockNodeAddWindow(dst_node, window, !move_tab_bar);
18201 }
18202 src_node->Windows.clear();
18203
18204 if (!move_tab_bar && src_node->TabBar)
18205 {
18206 if (dst_node->TabBar)
18207 dst_node->TabBar->SelectedTabId = src_node->TabBar->SelectedTabId;
18208 DockNodeRemoveTabBar(src_node);
18209 }
18210}
18211
18213{
18214 for (ImGuiWindow* window : node->Windows)
18215 {
18216 SetWindowPos(window, node->Pos, ImGuiCond_Always); // We don't assign directly to Pos because it can break the calculation of SizeContents on next frame
18217 SetWindowSize(window, node->Size, ImGuiCond_Always);
18218 }
18219}
18220
18222{
18223 if (node->HostWindow)
18224 {
18225 if (node->HostWindow->DockNodeAsHost == node)
18226 node->HostWindow->DockNodeAsHost = NULL;
18227 node->HostWindow = NULL;
18228 }
18229
18230 if (node->Windows.Size == 1)
18231 {
18232 node->VisibleWindow = node->Windows[0];
18233 node->Windows[0]->DockIsActive = false;
18234 }
18235
18236 if (node->TabBar)
18238}
18239
18240// Search function called once by root node in DockNodeUpdate()
18242{
18246 //ImGuiWindowClass WindowClassForMerges;
18247
18248 ImGuiDockNodeTreeInfo() { memset(this, 0, sizeof(*this)); }
18249};
18250
18252{
18253 if (node->Windows.Size > 0)
18254 {
18255 if (info->FirstNodeWithWindows == NULL)
18256 info->FirstNodeWithWindows = node;
18257 info->CountNodesWithWindows++;
18258 }
18259 if (node->IsCentralNode())
18260 {
18261 IM_ASSERT(info->CentralNode == NULL); // Should be only one
18262 IM_ASSERT(node->IsLeafNode() && "If you get this assert: please submit .ini file + repro of actions leading to this.");
18263 info->CentralNode = node;
18264 }
18265 if (info->CountNodesWithWindows > 1 && info->CentralNode != NULL)
18266 return;
18267 if (node->ChildNodes[0])
18268 DockNodeFindInfo(node->ChildNodes[0], info);
18269 if (node->ChildNodes[1])
18270 DockNodeFindInfo(node->ChildNodes[1], info);
18271}
18272
18274{
18275 IM_ASSERT(id != 0);
18276 for (ImGuiWindow* window : node->Windows)
18277 if (window->ID == id)
18278 return window;
18279 return NULL;
18280}
18281
18282// - Remove inactive windows/nodes.
18283// - Update visibility flag.
18285{
18286 ImGuiContext& g = *GImGui;
18287 IM_ASSERT(node->ParentNode == NULL || node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node);
18288
18289 // Inherit most flags
18290 if (node->ParentNode)
18292
18293 // Recurse into children
18294 // There is the possibility that one of our child becoming empty will delete itself and moving its sibling contents into 'node'.
18295 // If 'node->ChildNode[0]' delete itself, then 'node->ChildNode[1]->Windows' will be moved into 'node'
18296 // If 'node->ChildNode[1]' delete itself, then 'node->ChildNode[0]->Windows' will be moved into 'node' and the "remove inactive windows" loop will have run twice on those windows (harmless)
18297 node->HasCentralNodeChild = false;
18298 if (node->ChildNodes[0])
18300 if (node->ChildNodes[1])
18302
18303 // Remove inactive windows, collapse nodes
18304 // Merge node flags overrides stored in windows
18306 for (int window_n = 0; window_n < node->Windows.Size; window_n++)
18307 {
18308 ImGuiWindow* window = node->Windows[window_n];
18309 IM_ASSERT(window->DockNode == node);
18310
18311 bool node_was_active = (node->LastFrameActive + 1 == g.FrameCount);
18312 bool remove = false;
18313 remove |= node_was_active && (window->LastFrameActive + 1 < g.FrameCount);
18314 remove |= node_was_active && (node->WantCloseAll || node->WantCloseTabId == window->TabId) && window->HasCloseButton && !(window->Flags & ImGuiWindowFlags_UnsavedDocument); // Submit all _expected_ closure from last frame
18315 remove |= (window->DockTabWantClose);
18316 if (remove)
18317 {
18318 window->DockTabWantClose = false;
18319 if (node->Windows.Size == 1 && !node->IsCentralNode())
18320 {
18323 DockNodeRemoveWindow(node, window, node->ID); // Will delete the node so it'll be invalid on return
18324 return;
18325 }
18326 DockNodeRemoveWindow(node, window, node->ID);
18327 window_n--;
18328 continue;
18329 }
18330
18331 // FIXME-DOCKING: Missing policies for conflict resolution, hence the "Experimental" tag on this.
18332 //node->LocalFlagsInWindow &= ~window->WindowClass.DockNodeFlagsOverrideClear;
18334 }
18335 node->UpdateMergedFlags();
18336
18337 // Auto-hide tab bar option
18338 ImGuiDockNodeFlags node_flags = node->MergedFlags;
18339 if (node->WantHiddenTabBarUpdate && node->Windows.Size == 1 && (node_flags & ImGuiDockNodeFlags_AutoHideTabBar) && !node->IsHiddenTabBar())
18340 node->WantHiddenTabBarToggle = true;
18341 node->WantHiddenTabBarUpdate = false;
18342
18343 // Cancel toggling if we know our tab bar is enforced to be hidden at all times
18345 node->WantHiddenTabBarToggle = false;
18346
18347 // Apply toggles at a single point of the frame (here!)
18348 if (node->Windows.Size > 1)
18350 else if (node->WantHiddenTabBarToggle)
18352 node->WantHiddenTabBarToggle = false;
18353
18355}
18356
18357// This is rarely called as DockNodeUpdateForRootNode() generally does it most frames.
18359{
18360 node->HasCentralNodeChild = false;
18361 if (node->ChildNodes[0])
18363 if (node->ChildNodes[1])
18365 if (node->IsRootNode())
18366 {
18367 ImGuiDockNode* mark_node = node->CentralNode;
18368 while (mark_node)
18369 {
18370 mark_node->HasCentralNodeChild = true;
18371 mark_node = mark_node->ParentNode;
18372 }
18373 }
18374}
18375
18377{
18378 // Update visibility flag
18379 bool is_visible = (node->ParentNode == NULL) ? node->IsDockSpace() : node->IsCentralNode();
18380 is_visible |= (node->Windows.Size > 0);
18381 is_visible |= (node->ChildNodes[0] && node->ChildNodes[0]->IsVisible);
18382 is_visible |= (node->ChildNodes[1] && node->ChildNodes[1]->IsVisible);
18383 node->IsVisible = is_visible;
18384}
18385
18387{
18388 ImGuiContext& g = *GImGui;
18389 IM_ASSERT(node->WantMouseMove == true);
18390 StartMouseMovingWindow(window);
18391 g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - node->Pos;
18392 g.MovingWindow = window; // If we are docked into a non moveable root window, StartMouseMovingWindow() won't set g.MovingWindow. Override that decision.
18393 node->WantMouseMove = false;
18394}
18395
18396// Update CentralNode, OnlyNodeWithWindows, LastFocusedNodeID. Copy window class.
18398{
18400
18401 // - Setup central node pointers
18402 // - Find if there's only a single visible window in the hierarchy (in which case we need to display a regular title bar -> FIXME-DOCK: that last part is not done yet!)
18403 // Cannot merge this with DockNodeUpdateFlagsAndCollapse() because FirstNodeWithWindows is found after window removal and child collapsing
18405 DockNodeFindInfo(node, &info);
18406 node->CentralNode = info.CentralNode;
18407 node->OnlyNodeWithWindows = (info.CountNodesWithWindows == 1) ? info.FirstNodeWithWindows : NULL;
18409 if (node->LastFocusedNodeId == 0 && info.FirstNodeWithWindows != NULL)
18411
18412 // Copy the window class from of our first window so it can be used for proper dock filtering.
18413 // When node has mixed windows, prioritize the class with the most constraint (DockingAllowUnclassed = false) as the reference to copy.
18414 // FIXME-DOCK: We don't recurse properly, this code could be reworked to work from DockNodeUpdateScanRec.
18415 if (ImGuiDockNode* first_node_with_windows = info.FirstNodeWithWindows)
18416 {
18417 node->WindowClass = first_node_with_windows->Windows[0]->WindowClass;
18418 for (int n = 1; n < first_node_with_windows->Windows.Size; n++)
18419 if (first_node_with_windows->Windows[n]->WindowClass.DockingAllowUnclassed == false)
18420 {
18421 node->WindowClass = first_node_with_windows->Windows[n]->WindowClass;
18422 break;
18423 }
18424 }
18425
18426 ImGuiDockNode* mark_node = node->CentralNode;
18427 while (mark_node)
18428 {
18429 mark_node->HasCentralNodeChild = true;
18430 mark_node = mark_node->ParentNode;
18431 }
18432}
18433
18434static void DockNodeSetupHostWindow(ImGuiDockNode* node, ImGuiWindow* host_window)
18435{
18436 // Remove ourselves from any previous different host window
18437 // This can happen if a user mistakenly does (see #4295 for details):
18438 // - N+0: DockBuilderAddNode(id, 0) // missing ImGuiDockNodeFlags_DockSpace
18439 // - N+1: NewFrame() // will create floating host window for that node
18440 // - N+1: DockSpace(id) // requalify node as dockspace, moving host window
18441 if (node->HostWindow && node->HostWindow != host_window && node->HostWindow->DockNodeAsHost == node)
18442 node->HostWindow->DockNodeAsHost = NULL;
18443
18444 host_window->DockNodeAsHost = node;
18445 node->HostWindow = host_window;
18446}
18447
18449{
18450 ImGuiContext& g = *GImGui;
18452 node->LastFrameAlive = g.FrameCount;
18453 node->IsBgDrawnThisFrame = false;
18454
18455 node->CentralNode = node->OnlyNodeWithWindows = NULL;
18456 if (node->IsRootNode())
18458
18459 // Remove tab bar if not needed
18460 if (node->TabBar && node->IsNoTabBar())
18462
18463 // Early out for hidden root dock nodes (when all DockId references are in inactive windows, or there is only 1 floating window holding on the DockId)
18464 bool want_to_hide_host_window = false;
18465 if (node->IsFloatingNode())
18466 {
18467 if (node->Windows.Size <= 1 && node->IsLeafNode())
18468 if (!g.IO.ConfigDockingAlwaysTabBar && (node->Windows.Size == 0 || !node->Windows[0]->WindowClass.DockingAlwaysTabBar))
18469 want_to_hide_host_window = true;
18470 if (node->CountNodeWithWindows == 0)
18471 want_to_hide_host_window = true;
18472 }
18473 if (want_to_hide_host_window)
18474 {
18475 if (node->Windows.Size == 1)
18476 {
18477 // Floating window pos/size is authoritative
18478 ImGuiWindow* single_window = node->Windows[0];
18479 node->Pos = single_window->Pos;
18480 node->Size = single_window->SizeFull;
18482
18483 // Transfer focus immediately so when we revert to a regular window it is immediately selected
18484 if (node->HostWindow && g.NavWindow == node->HostWindow)
18485 FocusWindow(single_window);
18486 if (node->HostWindow)
18487 {
18488 IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Node %08X transfer Viewport %08X->%08X to Window '%s'\n", node->ID, node->HostWindow->Viewport->ID, single_window->ID, single_window->Name);
18489 single_window->Viewport = node->HostWindow->Viewport;
18490 single_window->ViewportId = node->HostWindow->ViewportId;
18491 if (node->HostWindow->ViewportOwned)
18492 {
18493 single_window->Viewport->ID = single_window->ID;
18494 single_window->Viewport->Window = single_window;
18495 single_window->ViewportOwned = true;
18496 }
18497 }
18498 node->RefViewportId = single_window->ViewportId;
18499 }
18500
18503 node->WantCloseAll = false;
18504 node->WantCloseTabId = 0;
18505 node->HasCloseButton = node->HasWindowMenuButton = false;
18506 node->LastFrameActive = g.FrameCount;
18507
18508 if (node->WantMouseMove && node->Windows.Size == 1)
18510 return;
18511 }
18512
18513 // In some circumstance we will defer creating the host window (so everything will be kept hidden),
18514 // while the expected visible window is resizing itself.
18515 // This is important for first-time (no ini settings restored) single window when io.ConfigDockingAlwaysTabBar is enabled,
18516 // otherwise the node ends up using the minimum window size. Effectively those windows will take an extra frame to show up:
18517 // N+0: Begin(): window created (with no known size), node is created
18518 // N+1: DockNodeUpdate(): node skip creating host window / Begin(): window size applied, not visible
18519 // N+2: DockNodeUpdate(): node can create host window / Begin(): window becomes visible
18520 // We could remove this frame if we could reliably calculate the expected window size during node update, before the Begin() code.
18521 // It would require a generalization of CalcWindowExpectedSize(), probably extracting code away from Begin().
18522 // In reality it isn't very important as user quickly ends up with size data in .ini file.
18523 if (node->IsVisible && node->HostWindow == NULL && node->IsFloatingNode() && node->IsLeafNode())
18524 {
18525 IM_ASSERT(node->Windows.Size > 0);
18526 ImGuiWindow* ref_window = NULL;
18527 if (node->SelectedTabId != 0) // Note that we prune single-window-node settings on .ini loading, so this is generally 0 for them!
18528 ref_window = DockNodeFindWindowByID(node, node->SelectedTabId);
18529 if (ref_window == NULL)
18530 ref_window = node->Windows[0];
18531 if (ref_window->AutoFitFramesX > 0 || ref_window->AutoFitFramesY > 0)
18532 {
18534 return;
18535 }
18536 }
18537
18538 const ImGuiDockNodeFlags node_flags = node->MergedFlags;
18539
18540 // Decide if the node will have a close button and a window menu button
18541 node->HasWindowMenuButton = (node->Windows.Size > 0) && (node_flags & ImGuiDockNodeFlags_NoWindowMenuButton) == 0;
18542 node->HasCloseButton = false;
18543 for (ImGuiWindow* window : node->Windows)
18544 {
18545 // FIXME-DOCK: Setting DockIsActive here means that for single active window in a leaf node, DockIsActive will be cleared until the next Begin() call.
18546 node->HasCloseButton |= window->HasCloseButton;
18547 window->DockIsActive = (node->Windows.Size > 1);
18548 }
18549 if (node_flags & ImGuiDockNodeFlags_NoCloseButton)
18550 node->HasCloseButton = false;
18551
18552 // Bind or create host window
18553 ImGuiWindow* host_window = NULL;
18554 bool beginned_into_host_window = false;
18555 if (node->IsDockSpace())
18556 {
18557 // [Explicit root dockspace node]
18558 IM_ASSERT(node->HostWindow);
18559 host_window = node->HostWindow;
18560 }
18561 else
18562 {
18563 // [Automatic root or child nodes]
18564 if (node->IsRootNode() && node->IsVisible)
18565 {
18566 ImGuiWindow* ref_window = (node->Windows.Size > 0) ? node->Windows[0] : NULL;
18567
18568 // Sync Pos
18569 if (node->AuthorityForPos == ImGuiDataAuthority_Window && ref_window)
18570 SetNextWindowPos(ref_window->Pos);
18572 SetNextWindowPos(node->Pos);
18573
18574 // Sync Size
18575 if (node->AuthorityForSize == ImGuiDataAuthority_Window && ref_window)
18576 SetNextWindowSize(ref_window->SizeFull);
18578 SetNextWindowSize(node->Size);
18579
18580 // Sync Collapsed
18581 if (node->AuthorityForSize == ImGuiDataAuthority_Window && ref_window)
18582 SetNextWindowCollapsed(ref_window->Collapsed);
18583
18584 // Sync Viewport
18585 if (node->AuthorityForViewport == ImGuiDataAuthority_Window && ref_window)
18586 SetNextWindowViewport(ref_window->ViewportId);
18587 else if (node->AuthorityForViewport == ImGuiDataAuthority_Window && node->RefViewportId != 0)
18589
18591
18592 // Begin into the host window
18593 char window_label[20];
18594 DockNodeGetHostWindowTitle(node, window_label, IM_ARRAYSIZE(window_label));
18598 window_flags |= ImGuiWindowFlags_NoTitleBar;
18599
18600 SetNextWindowBgAlpha(0.0f); // Don't set ImGuiWindowFlags_NoBackground because it disables borders
18602 Begin(window_label, NULL, window_flags);
18603 PopStyleVar();
18604 beginned_into_host_window = true;
18605
18606 host_window = g.CurrentWindow;
18607 DockNodeSetupHostWindow(node, host_window);
18608 host_window->DC.CursorPos = host_window->Pos;
18609 node->Pos = host_window->Pos;
18610 node->Size = host_window->Size;
18611
18612 // We set ImGuiWindowFlags_NoFocusOnAppearing because we don't want the host window to take full focus (e.g. steal NavWindow)
18613 // But we still it bring it to the front of display. There's no way to choose this precise behavior via window flags.
18614 // One simple case to ponder if: window A has a toggle to create windows B/C/D. Dock B/C/D together, clear the toggle and enable it again.
18615 // When reappearing B/C/D will request focus and be moved to the top of the display pile, but they are not linked to the dock host window
18616 // during the frame they appear. The dock host window would keep its old display order, and the sorting in EndFrame would move B/C/D back
18617 // after the dock host window, losing their top-most status.
18618 if (node->HostWindow->Appearing)
18620
18622 }
18623 else if (node->ParentNode)
18624 {
18625 node->HostWindow = host_window = node->ParentNode->HostWindow;
18627 }
18628 if (node->WantMouseMove && node->HostWindow)
18630 }
18631 node->RefViewportId = 0; // Clear when we have a host window
18632
18633 // Update focused node (the one whose title bar is highlight) within a node tree
18634 if (node->IsSplitNode())
18635 IM_ASSERT(node->TabBar == NULL);
18636 if (node->IsRootNode())
18637 if (ImGuiWindow* p_window = g.NavWindow ? g.NavWindow->RootWindow : NULL)
18638 while (p_window != NULL && p_window->DockNode != NULL)
18639 {
18640 ImGuiDockNode* p_node = DockNodeGetRootNode(p_window->DockNode);
18641 if (p_node == node)
18642 {
18643 node->LastFocusedNodeId = p_window->DockNode->ID; // Note: not using root node ID!
18644 break;
18645 }
18646 p_window = p_node->HostWindow ? p_node->HostWindow->RootWindow : NULL;
18647 }
18648
18649 // Register a hit-test hole in the window unless we are currently dragging a window that is compatible with our dockspace
18650 ImGuiDockNode* central_node = node->CentralNode;
18651 const bool central_node_hole = node->IsRootNode() && host_window && (node_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0 && central_node != NULL && central_node->IsEmpty();
18652 bool central_node_hole_register_hit_test_hole = central_node_hole;
18653 if (central_node_hole)
18654 if (const ImGuiPayload* payload = ImGui::GetDragDropPayload())
18655 if (payload->IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW) && DockNodeIsDropAllowed(host_window, *(ImGuiWindow**)payload->Data))
18656 central_node_hole_register_hit_test_hole = false;
18657 if (central_node_hole_register_hit_test_hole)
18658 {
18659 // We add a little padding to match the "resize from edges" behavior and allow grabbing the splitter easily.
18660 // (But we only add it if there's something else on the other side of the hole, otherwise for e.g. fullscreen
18661 // covering passthru node we'd have a gap on the edge not covered by the hole)
18662 IM_ASSERT(node->IsDockSpace()); // We cannot pass this flag without the DockSpace() api. Testing this because we also setup the hole in host_window->ParentNode
18663 ImGuiDockNode* root_node = DockNodeGetRootNode(central_node);
18664 ImRect root_rect(root_node->Pos, root_node->Pos + root_node->Size);
18665 ImRect hole_rect(central_node->Pos, central_node->Pos + central_node->Size);
18666 if (hole_rect.Min.x > root_rect.Min.x) { hole_rect.Min.x += g.WindowsBorderHoverPadding; }
18667 if (hole_rect.Max.x < root_rect.Max.x) { hole_rect.Max.x -= g.WindowsBorderHoverPadding; }
18668 if (hole_rect.Min.y > root_rect.Min.y) { hole_rect.Min.y += g.WindowsBorderHoverPadding; }
18669 if (hole_rect.Max.y < root_rect.Max.y) { hole_rect.Max.y -= g.WindowsBorderHoverPadding; }
18670 //GetForegroundDrawList()->AddRect(hole_rect.Min, hole_rect.Max, IM_COL32(255, 0, 0, 255));
18671 if (central_node_hole && !hole_rect.IsInverted())
18672 {
18673 SetWindowHitTestHole(host_window, hole_rect.Min, hole_rect.Max - hole_rect.Min);
18674 if (host_window->ParentWindow)
18675 SetWindowHitTestHole(host_window->ParentWindow, hole_rect.Min, hole_rect.Max - hole_rect.Min);
18676 }
18677 }
18678
18679 // Update position/size, process and draw resizing splitters
18680 if (node->IsRootNode() && host_window)
18681 {
18682 DockNodeTreeUpdatePosSize(node, host_window->Pos, host_window->Size);
18687 PopStyleColor(3);
18688 }
18689
18690 // Draw empty node background (currently can only be the Central Node)
18691 if (host_window && node->IsEmpty() && node->IsVisible)
18692 {
18695 if (node->LastBgColor != 0)
18696 host_window->DrawList->AddRectFilled(node->Pos, node->Pos + node->Size, node->LastBgColor);
18697 node->IsBgDrawnThisFrame = true;
18698 }
18699
18700 // Draw whole dockspace background if ImGuiDockNodeFlags_PassthruCentralNode if set.
18701 // We need to draw a background at the root level if requested by ImGuiDockNodeFlags_PassthruCentralNode, but we will only know the correct pos/size
18702 // _after_ processing the resizing splitters. So we are using the DrawList channel splitting facility to submit drawing primitives out of order!
18703 const bool render_dockspace_bg = node->IsRootNode() && host_window && (node_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0;
18704 if (render_dockspace_bg && node->IsVisible)
18705 {
18707 if (central_node_hole)
18708 RenderRectFilledWithHole(host_window->DrawList, node->Rect(), central_node->Rect(), GetColorU32(ImGuiCol_WindowBg), 0.0f);
18709 else
18710 host_window->DrawList->AddRectFilled(node->Pos, node->Pos + node->Size, GetColorU32(ImGuiCol_WindowBg), 0.0f);
18711 }
18712
18713 // Draw and populate Tab Bar
18714 if (host_window)
18716 if (host_window && node->Windows.Size > 0)
18717 {
18718 DockNodeUpdateTabBar(node, host_window);
18719 }
18720 else
18721 {
18722 node->WantCloseAll = false;
18723 node->WantCloseTabId = 0;
18724 node->IsFocused = false;
18725 }
18726 if (node->TabBar && node->TabBar->SelectedTabId)
18727 node->SelectedTabId = node->TabBar->SelectedTabId;
18728 else if (node->Windows.Size > 0)
18729 node->SelectedTabId = node->Windows[0]->TabId;
18730
18731 // Draw payload drop target
18732 if (host_window && node->IsVisible)
18733 if (node->IsRootNode() && (g.MovingWindow == NULL || g.MovingWindow->RootWindowDockTree != host_window))
18734 BeginDockableDragDropTarget(host_window);
18735
18736 // We update this after DockNodeUpdateTabBar()
18737 node->LastFrameActive = g.FrameCount;
18738
18739 // Recurse into children
18740 // FIXME-DOCK FIXME-OPT: Should not need to recurse into children
18741 if (host_window)
18742 {
18743 if (node->ChildNodes[0])
18744 DockNodeUpdate(node->ChildNodes[0]);
18745 if (node->ChildNodes[1])
18746 DockNodeUpdate(node->ChildNodes[1]);
18747
18748 // Render outer borders last (after the tab bar)
18749 if (node->IsRootNode())
18750 RenderWindowOuterBorders(host_window);
18751 }
18752
18753 // End host window
18754 if (beginned_into_host_window) //-V1020
18755 End();
18756}
18757
18758// Compare TabItem nodes given the last known DockOrder (will persist in .ini file as hint), used to sort tabs when multiple tabs are added on the same frame.
18759static int IMGUI_CDECL TabItemComparerByDockOrder(const void* lhs, const void* rhs)
18760{
18761 ImGuiWindow* a = ((const ImGuiTabItem*)lhs)->Window;
18762 ImGuiWindow* b = ((const ImGuiTabItem*)rhs)->Window;
18763 if (int d = ((a->DockOrder == -1) ? INT_MAX : a->DockOrder) - ((b->DockOrder == -1) ? INT_MAX : b->DockOrder))
18764 return d;
18766}
18767
18768// Default handler for g.DockNodeWindowMenuHandler(): display the list of windows for a given dock-node.
18769// This is exceptionally stored in a function pointer to also user applications to tweak this menu (undocumented)
18770// Custom overrides may want to decorate, group, sort entries.
18771// Please note those are internal structures: if you copy this expect occasional breakage.
18772// (if you don't need to modify the "Tabs.Size == 1" behavior/path it is recommend you call this function in your handler)
18774{
18775 IM_UNUSED(ctx);
18776 if (tab_bar->Tabs.Size == 1)
18777 {
18778 // "Hide tab bar" option. Being one of our rare user-facing string we pull it from a table.
18780 node->WantHiddenTabBarToggle = true;
18781 }
18782 else
18783 {
18784 // Display a selectable list of windows in this docking node
18785 for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
18786 {
18787 ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
18789 continue;
18790 if (Selectable(TabBarGetTabName(tab_bar, tab), tab->ID == tab_bar->SelectedTabId))
18791 TabBarQueueFocus(tab_bar, tab);
18792 SameLine();
18793 Text(" ");
18794 }
18795 }
18796}
18797
18799{
18800 // Try to position the menu so it is more likely to stays within the same viewport
18801 ImGuiContext& g = *GImGui;
18803 SetNextWindowPos(ImVec2(node->Pos.x, node->Pos.y + GetFrameHeight()), ImGuiCond_Always, ImVec2(0.0f, 0.0f));
18804 else
18805 SetNextWindowPos(ImVec2(node->Pos.x + node->Size.x, node->Pos.y + GetFrameHeight()), ImGuiCond_Always, ImVec2(1.0f, 0.0f));
18806 if (BeginPopup("#WindowMenu"))
18807 {
18808 node->IsFocused = true;
18809 g.DockNodeWindowMenuHandler(&g, node, tab_bar);
18810 EndPopup();
18811 }
18812}
18813
18814// User helper to append/amend into a dock node tab bar. Most commonly used to add e.g. a "+" button.
18816{
18817 if (node->TabBar == NULL || node->HostWindow == NULL)
18818 return false;
18820 return false;
18821 if (node->TabBar->ID == 0)
18822 return false;
18823 Begin(node->HostWindow->Name);
18824 PushOverrideID(node->ID);
18825 bool ret = BeginTabBarEx(node->TabBar, node->TabBar->BarRect, node->TabBar->Flags);
18826 IM_UNUSED(ret);
18827 IM_ASSERT(ret);
18828 return true;
18829}
18830
18832{
18833 EndTabBar();
18834 PopID();
18835 End();
18836}
18837
18839{
18840 // CTRL+Tab highlight (only highlighting leaf node, not whole hierarchy)
18841 ImGuiContext& g = *GImGui;
18842 if (g.NavWindowingTarget)
18843 return (g.NavWindowingTarget->DockNode == node);
18844
18845 // FIXME-DOCKING: May want alternative to treat central node void differently? e.g. if (g.NavWindow == host_window)
18846 if (g.NavWindow && root_node->LastFocusedNodeId == node->ID)
18847 {
18848 // FIXME: This could all be backed in RootWindowForTitleBarHighlight? Probably need to reorganize for both dock nodes + other RootWindowForTitleBarHighlight users (not-node)
18849 ImGuiWindow* parent_window = g.NavWindow->RootWindow;
18850 while (parent_window->Flags & ImGuiWindowFlags_ChildMenu)
18851 parent_window = parent_window->ParentWindow->RootWindow;
18852 ImGuiDockNode* start_parent_node = parent_window->DockNodeAsHost ? parent_window->DockNodeAsHost : parent_window->DockNode;
18853 for (ImGuiDockNode* parent_node = start_parent_node; parent_node != NULL; parent_node = parent_node->HostWindow ? parent_node->HostWindow->RootWindow->DockNode : NULL)
18854 if ((parent_node = ImGui::DockNodeGetRootNode(parent_node)) == root_node)
18855 return true;
18856 }
18857 return false;
18858}
18859
18860// Submit the tab bar corresponding to a dock node and various housekeeping details.
18862{
18863 ImGuiContext& g = *GImGui;
18864 ImGuiStyle& style = g.Style;
18865
18866 const bool node_was_active = (node->LastFrameActive + 1 == g.FrameCount);
18867 const bool closed_all = node->WantCloseAll && node_was_active;
18868 const ImGuiID closed_one = node->WantCloseTabId && node_was_active;
18869 node->WantCloseAll = false;
18870 node->WantCloseTabId = 0;
18871
18872 // Decide if we should use a focused title bar color
18873 bool is_focused = false;
18874 ImGuiDockNode* root_node = DockNodeGetRootNode(node);
18875 if (IsDockNodeTitleBarHighlighted(node, root_node))
18876 is_focused = true;
18877
18878 // Hidden tab bar will show a triangle on the upper-left (in Begin)
18879 if (node->IsHiddenTabBar() || node->IsNoTabBar())
18880 {
18881 node->VisibleWindow = (node->Windows.Size > 0) ? node->Windows[0] : NULL;
18882 node->IsFocused = is_focused;
18883 if (is_focused)
18884 node->LastFrameFocused = g.FrameCount;
18885 if (node->VisibleWindow)
18886 {
18887 // Notify root of visible window (used to display title in OS task bar)
18888 if (is_focused || root_node->VisibleWindow == NULL)
18889 root_node->VisibleWindow = node->VisibleWindow;
18890 if (node->TabBar)
18891 node->TabBar->VisibleTabId = node->VisibleWindow->TabId;
18892 }
18893 return;
18894 }
18895
18896 // Move ourselves to the Menu layer (so we can be accessed by tapping Alt) + undo SkipItems flag in order to draw over the title bar even if the window is collapsed
18897 bool backup_skip_item = host_window->SkipItems;
18898 if (!node->IsDockSpace())
18899 {
18900 host_window->SkipItems = false;
18901 host_window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
18902 }
18903
18904 // Use PushOverrideID() instead of PushID() to use the node id _without_ the host window ID.
18905 // This is to facilitate computing those ID from the outside, and will affect more or less only the ID of the collapse button, popup and tabs,
18906 // as docked windows themselves will override the stack with their own root ID.
18907 PushOverrideID(node->ID);
18908 ImGuiTabBar* tab_bar = node->TabBar;
18909 bool tab_bar_is_recreated = (tab_bar == NULL); // Tab bar are automatically destroyed when a node gets hidden
18910 if (tab_bar == NULL)
18911 {
18912 DockNodeAddTabBar(node);
18913 tab_bar = node->TabBar;
18914 }
18915
18916 ImGuiID focus_tab_id = 0;
18917 node->IsFocused = is_focused;
18918
18919 const ImGuiDockNodeFlags node_flags = node->MergedFlags;
18920 const bool has_window_menu_button = (node_flags & ImGuiDockNodeFlags_NoWindowMenuButton) == 0 && (style.WindowMenuButtonPosition != ImGuiDir_None);
18921
18922 // In a dock node, the Collapse Button turns into the Window Menu button.
18923 // FIXME-DOCK FIXME-OPT: Could we recycle popups id across multiple dock nodes?
18924 if (has_window_menu_button && IsPopupOpen("#WindowMenu"))
18925 {
18926 ImGuiID next_selected_tab_id = tab_bar->NextSelectedTabId;
18927 DockNodeWindowMenuUpdate(node, tab_bar);
18928 if (tab_bar->NextSelectedTabId != 0 && tab_bar->NextSelectedTabId != next_selected_tab_id)
18929 focus_tab_id = tab_bar->NextSelectedTabId;
18930 is_focused |= node->IsFocused;
18931 }
18932
18933 // Layout
18934 ImRect title_bar_rect, tab_bar_rect;
18935 ImVec2 window_menu_button_pos;
18936 ImVec2 close_button_pos;
18937 DockNodeCalcTabBarLayout(node, &title_bar_rect, &tab_bar_rect, &window_menu_button_pos, &close_button_pos);
18938
18939 // Submit new tabs, they will be added as Unsorted and sorted below based on relative DockOrder value.
18940 const int tabs_count_old = tab_bar->Tabs.Size;
18941 for (int window_n = 0; window_n < node->Windows.Size; window_n++)
18942 {
18943 ImGuiWindow* window = node->Windows[window_n];
18944 if (TabBarFindTabByID(tab_bar, window->TabId) == NULL)
18945 TabBarAddTab(tab_bar, ImGuiTabItemFlags_Unsorted, window);
18946 }
18947
18948 // Title bar
18949 if (is_focused)
18950 node->LastFrameFocused = g.FrameCount;
18951 ImU32 title_bar_col = GetColorU32(host_window->Collapsed ? ImGuiCol_TitleBgCollapsed : is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
18952 ImDrawFlags rounding_flags = CalcRoundingFlagsForRectInRect(title_bar_rect, host_window->Rect(), g.Style.DockingSeparatorSize);
18953 host_window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, host_window->WindowRounding, rounding_flags);
18954
18955 // Docking/Collapse button
18956 if (has_window_menu_button)
18957 {
18958 if (CollapseButton(host_window->GetID("#COLLAPSE"), window_menu_button_pos, node)) // == DockNodeGetWindowMenuButtonId(node)
18959 OpenPopup("#WindowMenu");
18960 if (IsItemActive())
18961 focus_tab_id = tab_bar->SelectedTabId;
18964 }
18965
18966 // If multiple tabs are appearing on the same frame, sort them based on their persistent DockOrder value
18967 int tabs_unsorted_start = tab_bar->Tabs.Size;
18968 for (int tab_n = tab_bar->Tabs.Size - 1; tab_n >= 0 && (tab_bar->Tabs[tab_n].Flags & ImGuiTabItemFlags_Unsorted); tab_n--)
18969 {
18970 // FIXME-DOCK: Consider only clearing the flag after the tab has been alive for a few consecutive frames, allowing late comers to not break sorting?
18971 tab_bar->Tabs[tab_n].Flags &= ~ImGuiTabItemFlags_Unsorted;
18972 tabs_unsorted_start = tab_n;
18973 }
18974 if (tab_bar->Tabs.Size > tabs_unsorted_start)
18975 {
18976 IMGUI_DEBUG_LOG_DOCKING("[docking] In node 0x%08X: %d new appearing tabs:%s\n", node->ID, tab_bar->Tabs.Size - tabs_unsorted_start, (tab_bar->Tabs.Size > tabs_unsorted_start + 1) ? " (will sort)" : "");
18977 for (int tab_n = tabs_unsorted_start; tab_n < tab_bar->Tabs.Size; tab_n++)
18978 {
18979 ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
18980 IM_UNUSED(tab);
18981 IMGUI_DEBUG_LOG_DOCKING("[docking] - Tab 0x%08X '%s' Order %d\n", tab->ID, TabBarGetTabName(tab_bar, tab), tab->Window ? tab->Window->DockOrder : -1);
18982 }
18983 IMGUI_DEBUG_LOG_DOCKING("[docking] SelectedTabId = 0x%08X, NavWindow->TabId = 0x%08X\n", node->SelectedTabId, g.NavWindow ? g.NavWindow->TabId : -1);
18984 if (tab_bar->Tabs.Size > tabs_unsorted_start + 1)
18985 ImQsort(tab_bar->Tabs.Data + tabs_unsorted_start, tab_bar->Tabs.Size - tabs_unsorted_start, sizeof(ImGuiTabItem), TabItemComparerByDockOrder);
18986 }
18987
18988 // Apply NavWindow focus back to the tab bar
18989 if (g.NavWindow && g.NavWindow->RootWindow->DockNode == node)
18990 tab_bar->SelectedTabId = g.NavWindow->RootWindow->TabId;
18991
18992 // Selected newly added tabs, or persistent tab ID if the tab bar was just recreated
18993 if (tab_bar_is_recreated && TabBarFindTabByID(tab_bar, node->SelectedTabId) != NULL)
18994 tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = node->SelectedTabId;
18995 else if (tab_bar->Tabs.Size > tabs_count_old)
18996 tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = tab_bar->Tabs.back().Window->TabId;
18997
18998 // Begin tab bar
18999 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs; // | ImGuiTabBarFlags_NoTabListScrollingButtons);
19000 tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode;// | ImGuiTabBarFlags_FittingPolicyScroll;
19002 if (!host_window->Collapsed && is_focused)
19003 tab_bar_flags |= ImGuiTabBarFlags_IsFocused;
19004 tab_bar->ID = GetID("#TabBar");
19005 tab_bar->SeparatorMinX = node->Pos.x + host_window->WindowBorderSize; // Separator cover the whole node width
19006 tab_bar->SeparatorMaxX = node->Pos.x + node->Size.x - host_window->WindowBorderSize;
19007 BeginTabBarEx(tab_bar, tab_bar_rect, tab_bar_flags);
19008 //host_window->DrawList->AddRect(tab_bar_rect.Min, tab_bar_rect.Max, IM_COL32(255,0,255,255));
19009
19010 // Backup style colors
19011 ImVec4 backup_style_cols[ImGuiWindowDockStyleCol_COUNT];
19012 for (int color_n = 0; color_n < ImGuiWindowDockStyleCol_COUNT; color_n++)
19013 backup_style_cols[color_n] = g.Style.Colors[GWindowDockStyleColors[color_n]];
19014
19015 // Submit actual tabs
19016 node->VisibleWindow = NULL;
19017 for (int window_n = 0; window_n < node->Windows.Size; window_n++)
19018 {
19019 ImGuiWindow* window = node->Windows[window_n];
19020 if ((closed_all || closed_one == window->TabId) && window->HasCloseButton && !(window->Flags & ImGuiWindowFlags_UnsavedDocument))
19021 continue;
19022 if (window->LastFrameActive + 1 >= g.FrameCount || !node_was_active)
19023 {
19024 ImGuiTabItemFlags tab_item_flags = 0;
19025 tab_item_flags |= window->WindowClass.TabItemFlagsOverrideSet;
19027 tab_item_flags |= ImGuiTabItemFlags_UnsavedDocument;
19030
19031 // Apply stored style overrides for the window
19032 for (int color_n = 0; color_n < ImGuiWindowDockStyleCol_COUNT; color_n++)
19034
19035 // Note that TabItemEx() calls TabBarCalcTabID() so our tab item ID will ignore the current ID stack (rightly so)
19036 bool tab_open = true;
19037 TabItemEx(tab_bar, window->Name, window->HasCloseButton ? &tab_open : NULL, tab_item_flags, window);
19038 if (!tab_open)
19039 node->WantCloseTabId = window->TabId;
19040 if (tab_bar->VisibleTabId == window->TabId)
19041 node->VisibleWindow = window;
19042
19043 // Store last item data so it can be queried with IsItemXXX functions after the user Begin() call
19045 window->DC.DockTabItemRect = g.LastItemData.Rect;
19046
19047 // Update navigation ID on menu layer
19048 if (g.NavWindow && g.NavWindow->RootWindow == window && (window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0)
19049 host_window->NavLastIds[1] = window->TabId;
19050 }
19051 }
19052
19053 // Restore style colors
19054 for (int color_n = 0; color_n < ImGuiWindowDockStyleCol_COUNT; color_n++)
19055 g.Style.Colors[GWindowDockStyleColors[color_n]] = backup_style_cols[color_n];
19056
19057 // Notify root of visible window (used to display title in OS task bar)
19058 if (node->VisibleWindow)
19059 if (is_focused || root_node->VisibleWindow == NULL)
19060 root_node->VisibleWindow = node->VisibleWindow;
19061
19062 // Close button (after VisibleWindow was updated)
19063 // Note that VisibleWindow may have been overrided by CTRL+Tabbing, so VisibleWindow->TabId may be != from tab_bar->SelectedTabId
19064 const bool close_button_is_enabled = node->HasCloseButton && node->VisibleWindow && node->VisibleWindow->HasCloseButton;
19065 const bool close_button_is_visible = node->HasCloseButton;
19066 //const bool close_button_is_visible = close_button_is_enabled; // Most people would expect this behavior of not even showing the button (leaving a hole since we can't claim that space as other windows in the tba bar have one)
19067 if (close_button_is_visible)
19068 {
19069 if (!close_button_is_enabled)
19070 {
19072 PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_Text] * ImVec4(1.0f,1.0f,1.0f,0.4f));
19073 }
19074 if (CloseButton(host_window->GetID("#CLOSE"), close_button_pos))
19075 {
19076 node->WantCloseAll = true;
19077 for (int n = 0; n < tab_bar->Tabs.Size; n++)
19078 TabBarCloseTab(tab_bar, &tab_bar->Tabs[n]);
19079 }
19080 //if (IsItemActive())
19081 // focus_tab_id = tab_bar->SelectedTabId;
19082 if (!close_button_is_enabled)
19083 {
19084 PopStyleColor();
19085 PopItemFlag();
19086 }
19087 }
19088
19089 // When clicking on the title bar outside of tabs, we still focus the selected tab for that node
19090 // FIXME: TabItems submitted earlier use AllowItemOverlap so we manually perform a more specific test for now (hovered || held) in order to not cover them.
19091 ImGuiID title_bar_id = host_window->GetID("#TITLEBAR");
19092 if (g.HoveredId == 0 || g.HoveredId == title_bar_id || g.ActiveId == title_bar_id)
19093 {
19094 // AllowOverlap mode required for appending into dock node tab bar,
19095 // otherwise dragging window will steal HoveredId and amended tabs cannot get them.
19096 bool held;
19097 KeepAliveID(title_bar_id);
19098 ButtonBehavior(title_bar_rect, title_bar_id, NULL, &held, ImGuiButtonFlags_AllowOverlap);
19099 if (g.HoveredId == title_bar_id)
19100 {
19101 g.LastItemData.ID = title_bar_id;
19102 }
19103 if (held)
19104 {
19105 if (IsMouseClicked(0))
19106 focus_tab_id = tab_bar->SelectedTabId;
19107
19108 // Forward moving request to selected window
19109 if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId))
19110 StartMouseMovingWindowOrNode(tab->Window ? tab->Window : node->HostWindow, node, false); // Undock from tab bar empty space
19111 }
19112 }
19113
19114 // Forward focus from host node to selected window
19115 //if (is_focused && g.NavWindow == host_window && !g.NavWindowingTarget)
19116 // focus_tab_id = tab_bar->SelectedTabId;
19117
19118 // When clicked on a tab we requested focus to the docked child
19119 // This overrides the value set by "forward focus from host node to selected window".
19120 if (tab_bar->NextSelectedTabId)
19121 focus_tab_id = tab_bar->NextSelectedTabId;
19122
19123 // Apply navigation focus
19124 if (focus_tab_id != 0)
19125 if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, focus_tab_id))
19126 if (tab->Window)
19127 {
19128 FocusWindow(tab->Window);
19129 NavInitWindow(tab->Window, false);
19130 }
19131
19132 EndTabBar();
19133 PopID();
19134
19135 // Restore SkipItems flag
19136 if (!node->IsDockSpace())
19137 {
19138 host_window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
19139 host_window->SkipItems = backup_skip_item;
19140 }
19141}
19142
19144{
19145 IM_ASSERT(node->TabBar == NULL);
19146 node->TabBar = IM_NEW(ImGuiTabBar);
19147}
19148
19150{
19151 if (node->TabBar == NULL)
19152 return;
19153 IM_DELETE(node->TabBar);
19154 node->TabBar = NULL;
19155}
19156
19157static bool DockNodeIsDropAllowedOne(ImGuiWindow* payload, ImGuiWindow* host_window)
19158{
19159 if (host_window->DockNodeAsHost && host_window->DockNodeAsHost->IsDockSpace() && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext)
19160 return false;
19161
19162 ImGuiWindowClass* host_class = host_window->DockNodeAsHost ? &host_window->DockNodeAsHost->WindowClass : &host_window->WindowClass;
19163 ImGuiWindowClass* payload_class = &payload->WindowClass;
19164 if (host_class->ClassId != payload_class->ClassId)
19165 {
19166 bool pass = false;
19167 if (host_class->ClassId != 0 && host_class->DockingAllowUnclassed && payload_class->ClassId == 0)
19168 pass = true;
19169 if (payload_class->ClassId != 0 && payload_class->DockingAllowUnclassed && host_class->ClassId == 0)
19170 pass = true;
19171 if (!pass)
19172 return false;
19173 }
19174
19175 // Prevent docking any window created above a popup
19176 // Technically we should support it (e.g. in the case of a long-lived modal window that had fancy docking features),
19177 // by e.g. adding a 'if (!ImGui::IsWindowWithinBeginStackOf(host_window, popup_window))' test.
19178 // But it would requires more work on our end because the dock host windows is technically created in NewFrame()
19179 // and our ->ParentXXX and ->RootXXX pointers inside windows are currently mislading or lacking.
19180 ImGuiContext& g = *GImGui;
19181 for (int i = g.OpenPopupStack.Size - 1; i >= 0; i--)
19182 if (ImGuiWindow* popup_window = g.OpenPopupStack[i].Window)
19183 if (ImGui::IsWindowWithinBeginStackOf(payload, popup_window)) // Payload is created from within a popup begin stack.
19184 return false;
19185
19186 return true;
19187}
19188
19189static bool ImGui::DockNodeIsDropAllowed(ImGuiWindow* host_window, ImGuiWindow* root_payload)
19190{
19191 if (root_payload->DockNodeAsHost && root_payload->DockNodeAsHost->IsSplitNode()) // FIXME-DOCK: Missing filtering
19192 return true;
19193
19194 const int payload_count = root_payload->DockNodeAsHost ? root_payload->DockNodeAsHost->Windows.Size : 1;
19195 for (int payload_n = 0; payload_n < payload_count; payload_n++)
19196 {
19197 ImGuiWindow* payload = root_payload->DockNodeAsHost ? root_payload->DockNodeAsHost->Windows[payload_n] : root_payload;
19198 if (DockNodeIsDropAllowedOne(payload, host_window))
19199 return true;
19200 }
19201 return false;
19202}
19203
19204// window menu button == collapse button when not in a dock node.
19205// FIXME: This is similar to RenderWindowTitleBarContents(), may want to share code.
19206static void ImGui::DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_window_menu_button_pos, ImVec2* out_close_button_pos)
19207{
19208 ImGuiContext& g = *GImGui;
19209 ImGuiStyle& style = g.Style;
19210
19211 ImRect r = ImRect(node->Pos.x, node->Pos.y, node->Pos.x + node->Size.x, node->Pos.y + g.FontSize + g.Style.FramePadding.y * 2.0f);
19212 if (out_title_rect) { *out_title_rect = r; }
19213
19214 r.Min.x += style.WindowBorderSize;
19215 r.Max.x -= style.WindowBorderSize;
19216
19217 float button_sz = g.FontSize;
19218 r.Min.x += style.FramePadding.x;
19219 r.Max.x -= style.FramePadding.x;
19220 ImVec2 window_menu_button_pos = ImVec2(r.Min.x, r.Min.y + style.FramePadding.y);
19221 if (node->HasCloseButton)
19222 {
19223 if (out_close_button_pos) *out_close_button_pos = ImVec2(r.Max.x - button_sz, r.Min.y + style.FramePadding.y);
19224 r.Max.x -= button_sz + style.ItemInnerSpacing.x;
19225 }
19227 {
19228 r.Min.x += button_sz + style.ItemInnerSpacing.x;
19229 }
19231 {
19232 window_menu_button_pos = ImVec2(r.Max.x - button_sz, r.Min.y + style.FramePadding.y);
19233 r.Max.x -= button_sz + style.ItemInnerSpacing.x;
19234 }
19235 if (out_tab_bar_rect) { *out_tab_bar_rect = r; }
19236 if (out_window_menu_button_pos) { *out_window_menu_button_pos = window_menu_button_pos; }
19237}
19238
19239void ImGui::DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& pos_new, ImVec2& size_new, ImGuiDir dir, ImVec2 size_new_desired)
19240{
19241 ImGuiContext& g = *GImGui;
19242 const float dock_spacing = g.Style.ItemInnerSpacing.x;
19243 const ImGuiAxis axis = (dir == ImGuiDir_Left || dir == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y;
19244 pos_new[axis ^ 1] = pos_old[axis ^ 1];
19245 size_new[axis ^ 1] = size_old[axis ^ 1];
19246
19247 // Distribute size on given axis (with a desired size or equally)
19248 const float w_avail = size_old[axis] - dock_spacing;
19249 if (size_new_desired[axis] > 0.0f && size_new_desired[axis] <= w_avail * 0.5f)
19250 {
19251 size_new[axis] = size_new_desired[axis];
19252 size_old[axis] = IM_TRUNC(w_avail - size_new[axis]);
19253 }
19254 else
19255 {
19256 size_new[axis] = IM_TRUNC(w_avail * 0.5f);
19257 size_old[axis] = IM_TRUNC(w_avail - size_new[axis]);
19258 }
19259
19260 // Position each node
19261 if (dir == ImGuiDir_Right || dir == ImGuiDir_Down)
19262 {
19263 pos_new[axis] = pos_old[axis] + size_old[axis] + dock_spacing;
19264 }
19265 else if (dir == ImGuiDir_Left || dir == ImGuiDir_Up)
19266 {
19267 pos_new[axis] = pos_old[axis];
19268 pos_old[axis] = pos_new[axis] + size_new[axis] + dock_spacing;
19269 }
19270}
19271
19272// Retrieve the drop rectangles for a given direction or for the center + perform hit testing.
19273bool ImGui::DockNodeCalcDropRectsAndTestMousePos(const ImRect& parent, ImGuiDir dir, ImRect& out_r, bool outer_docking, ImVec2* test_mouse_pos)
19274{
19275 ImGuiContext& g = *GImGui;
19276
19277 const float parent_smaller_axis = ImMin(parent.GetWidth(), parent.GetHeight());
19278 const float hs_for_central_nodes = ImMin(g.FontSize * 1.5f, ImMax(g.FontSize * 0.5f, parent_smaller_axis / 8.0f));
19279 float hs_w; // Half-size, longer axis
19280 float hs_h; // Half-size, smaller axis
19281 ImVec2 off; // Distance from edge or center
19282 if (outer_docking)
19283 {
19284 //hs_w = ImTrunc(ImClamp(parent_smaller_axis - hs_for_central_nodes * 4.0f, g.FontSize * 0.5f, g.FontSize * 8.0f));
19285 //hs_h = ImTrunc(hs_w * 0.15f);
19286 //off = ImVec2(ImTrunc(parent.GetWidth() * 0.5f - GetFrameHeightWithSpacing() * 1.4f - hs_h), ImTrunc(parent.GetHeight() * 0.5f - GetFrameHeightWithSpacing() * 1.4f - hs_h));
19287 hs_w = ImTrunc(hs_for_central_nodes * 1.50f);
19288 hs_h = ImTrunc(hs_for_central_nodes * 0.80f);
19289 off = ImTrunc(ImVec2(parent.GetWidth() * 0.5f - hs_h, parent.GetHeight() * 0.5f - hs_h));
19290 }
19291 else
19292 {
19293 hs_w = ImTrunc(hs_for_central_nodes);
19294 hs_h = ImTrunc(hs_for_central_nodes * 0.90f);
19295 off = ImTrunc(ImVec2(hs_w * 2.40f, hs_w * 2.40f));
19296 }
19297
19298 ImVec2 c = ImTrunc(parent.GetCenter());
19299 if (dir == ImGuiDir_None) { out_r = ImRect(c.x - hs_w, c.y - hs_w, c.x + hs_w, c.y + hs_w); }
19300 else if (dir == ImGuiDir_Up) { out_r = ImRect(c.x - hs_w, c.y - off.y - hs_h, c.x + hs_w, c.y - off.y + hs_h); }
19301 else if (dir == ImGuiDir_Down) { out_r = ImRect(c.x - hs_w, c.y + off.y - hs_h, c.x + hs_w, c.y + off.y + hs_h); }
19302 else if (dir == ImGuiDir_Left) { out_r = ImRect(c.x - off.x - hs_h, c.y - hs_w, c.x - off.x + hs_h, c.y + hs_w); }
19303 else if (dir == ImGuiDir_Right) { out_r = ImRect(c.x + off.x - hs_h, c.y - hs_w, c.x + off.x + hs_h, c.y + hs_w); }
19304
19305 if (test_mouse_pos == NULL)
19306 return false;
19307
19308 ImRect hit_r = out_r;
19309 if (!outer_docking)
19310 {
19311 // Custom hit testing for the 5-way selection, designed to reduce flickering when moving diagonally between sides
19312 hit_r.Expand(ImTrunc(hs_w * 0.30f));
19313 ImVec2 mouse_delta = (*test_mouse_pos - c);
19314 float mouse_delta_len2 = ImLengthSqr(mouse_delta);
19315 float r_threshold_center = hs_w * 1.4f;
19316 float r_threshold_sides = hs_w * (1.4f + 1.2f);
19317 if (mouse_delta_len2 < r_threshold_center * r_threshold_center)
19318 return (dir == ImGuiDir_None);
19319 if (mouse_delta_len2 < r_threshold_sides * r_threshold_sides)
19320 return (dir == ImGetDirQuadrantFromDelta(mouse_delta.x, mouse_delta.y));
19321 }
19322 return hit_r.Contains(*test_mouse_pos);
19323}
19324
19325// host_node may be NULL if the window doesn't have a DockNode already.
19326// FIXME-DOCK: This is misnamed since it's also doing the filtering.
19327static void ImGui::DockNodePreviewDockSetup(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, ImGuiDockNode* payload_node, ImGuiDockPreviewData* data, bool is_explicit_target, bool is_outer_docking)
19328{
19329 ImGuiContext& g = *GImGui;
19330
19331 // There is an edge case when docking into a dockspace which only has inactive nodes.
19332 // In this case DockNodeTreeFindNodeByPos() will have selected a leaf node which is inactive.
19333 // Because the inactive leaf node doesn't have proper pos/size yet, we'll use the root node as reference.
19334 if (payload_node == NULL)
19335 payload_node = payload_window->DockNodeAsHost;
19336 ImGuiDockNode* ref_node_for_rect = (host_node && !host_node->IsVisible) ? DockNodeGetRootNode(host_node) : host_node;
19337 if (ref_node_for_rect)
19338 IM_ASSERT(ref_node_for_rect->IsVisible == true);
19339
19340 // Filter, figure out where we are allowed to dock
19341 ImGuiDockNodeFlags src_node_flags = payload_node ? payload_node->MergedFlags : payload_window->WindowClass.DockNodeFlagsOverrideSet;
19342 ImGuiDockNodeFlags dst_node_flags = host_node ? host_node->MergedFlags : host_window->WindowClass.DockNodeFlagsOverrideSet;
19343 data->IsCenterAvailable = true;
19344 if (is_outer_docking)
19345 data->IsCenterAvailable = false;
19346 else if (dst_node_flags & ImGuiDockNodeFlags_NoDockingOverMe)
19347 data->IsCenterAvailable = false;
19348 else if (host_node && (dst_node_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) && host_node->IsCentralNode())
19349 data->IsCenterAvailable = false;
19350 else if ((!host_node || !host_node->IsEmpty()) && payload_node && payload_node->IsSplitNode() && (payload_node->OnlyNodeWithWindows == NULL)) // Is _visibly_ split?
19351 data->IsCenterAvailable = false;
19352 else if ((src_node_flags & ImGuiDockNodeFlags_NoDockingOverOther) && (!host_node || !host_node->IsEmpty()))
19353 data->IsCenterAvailable = false;
19354 else if ((src_node_flags & ImGuiDockNodeFlags_NoDockingOverEmpty) && host_node && host_node->IsEmpty())
19355 data->IsCenterAvailable = false;
19356
19357 data->IsSidesAvailable = true;
19358 if ((dst_node_flags & ImGuiDockNodeFlags_NoDockingSplit) || g.IO.ConfigDockingNoSplit)
19359 data->IsSidesAvailable = false;
19360 else if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsCentralNode())
19361 data->IsSidesAvailable = false;
19362 else if (src_node_flags & ImGuiDockNodeFlags_NoDockingSplitOther)
19363 data->IsSidesAvailable = false;
19364
19365 // Build a tentative future node (reuse same structure because it is practical. Shape will be readjusted when previewing a split)
19366 data->FutureNode.HasCloseButton = (host_node ? host_node->HasCloseButton : host_window->HasCloseButton) || (payload_window->HasCloseButton);
19367 data->FutureNode.HasWindowMenuButton = host_node ? true : ((host_window->Flags & ImGuiWindowFlags_NoCollapse) == 0);
19368 data->FutureNode.Pos = ref_node_for_rect ? ref_node_for_rect->Pos : host_window->Pos;
19369 data->FutureNode.Size = ref_node_for_rect ? ref_node_for_rect->Size : host_window->Size;
19370
19371 // Calculate drop shapes geometry for allowed splitting directions
19372 IM_ASSERT(ImGuiDir_None == -1);
19373 data->SplitNode = host_node;
19374 data->SplitDir = ImGuiDir_None;
19375 data->IsSplitDirExplicit = false;
19376 if (!host_window->Collapsed)
19377 for (int dir = ImGuiDir_None; dir < ImGuiDir_COUNT; dir++)
19378 {
19379 if (dir == ImGuiDir_None && !data->IsCenterAvailable)
19380 continue;
19381 if (dir != ImGuiDir_None && !data->IsSidesAvailable)
19382 continue;
19383 if (DockNodeCalcDropRectsAndTestMousePos(data->FutureNode.Rect(), (ImGuiDir)dir, data->DropRectsDraw[dir+1], is_outer_docking, &g.IO.MousePos))
19384 {
19385 data->SplitDir = (ImGuiDir)dir;
19386 data->IsSplitDirExplicit = true;
19387 }
19388 }
19389
19390 // When docking without holding Shift, we only allow and preview docking when hovering over a drop rect or over the title bar
19391 data->IsDropAllowed = (data->SplitDir != ImGuiDir_None) || (data->IsCenterAvailable);
19392 if (!is_explicit_target && !data->IsSplitDirExplicit && !g.IO.ConfigDockingWithShift)
19393 data->IsDropAllowed = false;
19394
19395 // Calculate split area
19396 data->SplitRatio = 0.0f;
19397 if (data->SplitDir != ImGuiDir_None)
19398 {
19399 ImGuiDir split_dir = data->SplitDir;
19400 ImGuiAxis split_axis = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y;
19401 ImVec2 pos_new, pos_old = data->FutureNode.Pos;
19402 ImVec2 size_new, size_old = data->FutureNode.Size;
19403 DockNodeCalcSplitRects(pos_old, size_old, pos_new, size_new, split_dir, payload_window->Size);
19404
19405 // Calculate split ratio so we can pass it down the docking request
19406 float split_ratio = ImSaturate(size_new[split_axis] / data->FutureNode.Size[split_axis]);
19407 data->FutureNode.Pos = pos_new;
19408 data->FutureNode.Size = size_new;
19409 data->SplitRatio = (split_dir == ImGuiDir_Right || split_dir == ImGuiDir_Down) ? (1.0f - split_ratio) : (split_ratio);
19410 }
19411}
19412
19413static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* root_payload, const ImGuiDockPreviewData* data)
19414{
19415 ImGuiContext& g = *GImGui;
19416 IM_ASSERT(g.CurrentWindow == host_window); // Because we rely on font size to calculate tab sizes
19417
19418 // With this option, we only display the preview on the target viewport, and the payload viewport is made transparent.
19419 // To compensate for the single layer obstructed by the payload, we'll increase the alpha of the preview nodes.
19420 const bool is_transparent_payload = g.IO.ConfigDockingTransparentPayload;
19421
19422 // In case the two windows involved are on different viewports, we will draw the overlay on each of them.
19423 int overlay_draw_lists_count = 0;
19424 ImDrawList* overlay_draw_lists[2];
19425 overlay_draw_lists[overlay_draw_lists_count++] = GetForegroundDrawList(host_window->Viewport);
19426 if (host_window->Viewport != root_payload->Viewport && !is_transparent_payload)
19427 overlay_draw_lists[overlay_draw_lists_count++] = GetForegroundDrawList(root_payload->Viewport);
19428
19429 // Draw main preview rectangle
19430 const ImU32 overlay_col_main = GetColorU32(ImGuiCol_DockingPreview, is_transparent_payload ? 0.60f : 0.40f);
19431 const ImU32 overlay_col_drop = GetColorU32(ImGuiCol_DockingPreview, is_transparent_payload ? 0.90f : 0.70f);
19432 const ImU32 overlay_col_drop_hovered = GetColorU32(ImGuiCol_DockingPreview, is_transparent_payload ? 1.20f : 1.00f);
19433 const ImU32 overlay_col_lines = GetColorU32(ImGuiCol_NavWindowingHighlight, is_transparent_payload ? 0.80f : 0.60f);
19434
19435 // Display area preview
19436 const bool can_preview_tabs = (root_payload->DockNodeAsHost == NULL || root_payload->DockNodeAsHost->Windows.Size > 0);
19437 if (data->IsDropAllowed)
19438 {
19439 ImRect overlay_rect = data->FutureNode.Rect();
19440 if (data->SplitDir == ImGuiDir_None && can_preview_tabs)
19441 overlay_rect.Min.y += GetFrameHeight();
19442 if (data->SplitDir != ImGuiDir_None || data->IsCenterAvailable)
19443 for (int overlay_n = 0; overlay_n < overlay_draw_lists_count; overlay_n++)
19444 overlay_draw_lists[overlay_n]->AddRectFilled(overlay_rect.Min, overlay_rect.Max, overlay_col_main, host_window->WindowRounding, CalcRoundingFlagsForRectInRect(overlay_rect, host_window->Rect(), g.Style.DockingSeparatorSize));
19445 }
19446
19447 // Display tab shape/label preview unless we are splitting node (it generally makes the situation harder to read)
19448 if (data->IsDropAllowed && can_preview_tabs && data->SplitDir == ImGuiDir_None && data->IsCenterAvailable)
19449 {
19450 // Compute target tab bar geometry so we can locate our preview tabs
19451 ImRect tab_bar_rect;
19452 DockNodeCalcTabBarLayout(&data->FutureNode, NULL, &tab_bar_rect, NULL, NULL);
19453 ImVec2 tab_pos = tab_bar_rect.Min;
19454 if (host_node && host_node->TabBar)
19455 {
19456 if (!host_node->IsHiddenTabBar() && !host_node->IsNoTabBar())
19457 tab_pos.x += host_node->TabBar->WidthAllTabs + g.Style.ItemInnerSpacing.x; // We don't use OffsetNewTab because when using non-persistent-order tab bar it is incremented with each Tab submission.
19458 else
19459 tab_pos.x += g.Style.ItemInnerSpacing.x + TabItemCalcSize(host_node->Windows[0]).x;
19460 }
19461 else if (!(host_window->Flags & ImGuiWindowFlags_DockNodeHost))
19462 {
19463 tab_pos.x += g.Style.ItemInnerSpacing.x + TabItemCalcSize(host_window).x; // Account for slight offset which will be added when changing from title bar to tab bar
19464 }
19465
19466 // Draw tab shape/label preview (payload may be a loose window or a host window carrying multiple tabbed windows)
19467 if (root_payload->DockNodeAsHost)
19468 IM_ASSERT(root_payload->DockNodeAsHost->Windows.Size <= root_payload->DockNodeAsHost->TabBar->Tabs.Size);
19469 ImGuiTabBar* tab_bar_with_payload = root_payload->DockNodeAsHost ? root_payload->DockNodeAsHost->TabBar : NULL;
19470 const int payload_count = tab_bar_with_payload ? tab_bar_with_payload->Tabs.Size : 1;
19471 for (int payload_n = 0; payload_n < payload_count; payload_n++)
19472 {
19473 // DockNode's TabBar may have non-window Tabs manually appended by user
19474 ImGuiWindow* payload_window = tab_bar_with_payload ? tab_bar_with_payload->Tabs[payload_n].Window : root_payload;
19475 if (tab_bar_with_payload && payload_window == NULL)
19476 continue;
19477 if (!DockNodeIsDropAllowedOne(payload_window, host_window))
19478 continue;
19479
19480 // Calculate the tab bounding box for each payload window
19481 ImVec2 tab_size = TabItemCalcSize(payload_window);
19482 ImRect tab_bb(tab_pos.x, tab_pos.y, tab_pos.x + tab_size.x, tab_pos.y + tab_size.y);
19483 tab_pos.x += tab_size.x + g.Style.ItemInnerSpacing.x;
19484 const ImU32 overlay_col_text = GetColorU32(payload_window->DockStyle.Colors[ImGuiWindowDockStyleCol_Text]);
19485 const ImU32 overlay_col_tabs = GetColorU32(payload_window->DockStyle.Colors[ImGuiWindowDockStyleCol_TabSelected]);
19486 PushStyleColor(ImGuiCol_Text, overlay_col_text);
19487 for (int overlay_n = 0; overlay_n < overlay_draw_lists_count; overlay_n++)
19488 {
19490 if (!tab_bar_rect.Contains(tab_bb))
19491 overlay_draw_lists[overlay_n]->PushClipRect(tab_bar_rect.Min, tab_bar_rect.Max);
19492 TabItemBackground(overlay_draw_lists[overlay_n], tab_bb, tab_flags, overlay_col_tabs);
19493 TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, g.Style.FramePadding, payload_window->Name, 0, 0, false, NULL, NULL);
19494 if (!tab_bar_rect.Contains(tab_bb))
19495 overlay_draw_lists[overlay_n]->PopClipRect();
19496 }
19497 PopStyleColor();
19498 }
19499 }
19500
19501 // Display drop boxes
19502 const float overlay_rounding = ImMax(3.0f, g.Style.FrameRounding);
19503 for (int dir = ImGuiDir_None; dir < ImGuiDir_COUNT; dir++)
19504 {
19505 if (!data->DropRectsDraw[dir + 1].IsInverted())
19506 {
19507 ImRect draw_r = data->DropRectsDraw[dir + 1];
19508 ImRect draw_r_in = draw_r;
19509 draw_r_in.Expand(-2.0f);
19510 ImU32 overlay_col = (data->SplitDir == (ImGuiDir)dir && data->IsSplitDirExplicit) ? overlay_col_drop_hovered : overlay_col_drop;
19511 for (int overlay_n = 0; overlay_n < overlay_draw_lists_count; overlay_n++)
19512 {
19513 ImVec2 center = ImFloor(draw_r_in.GetCenter());
19514 overlay_draw_lists[overlay_n]->AddRectFilled(draw_r.Min, draw_r.Max, overlay_col, overlay_rounding);
19515 overlay_draw_lists[overlay_n]->AddRect(draw_r_in.Min, draw_r_in.Max, overlay_col_lines, overlay_rounding);
19516 if (dir == ImGuiDir_Left || dir == ImGuiDir_Right)
19517 overlay_draw_lists[overlay_n]->AddLine(ImVec2(center.x, draw_r_in.Min.y), ImVec2(center.x, draw_r_in.Max.y), overlay_col_lines);
19518 if (dir == ImGuiDir_Up || dir == ImGuiDir_Down)
19519 overlay_draw_lists[overlay_n]->AddLine(ImVec2(draw_r_in.Min.x, center.y), ImVec2(draw_r_in.Max.x, center.y), overlay_col_lines);
19520 }
19521 }
19522
19523 // Stop after ImGuiDir_None
19524 if ((host_node && (host_node->MergedFlags & ImGuiDockNodeFlags_NoDockingSplit)) || g.IO.ConfigDockingNoSplit)
19525 return;
19526 }
19527}
19528
19529//-----------------------------------------------------------------------------
19530// Docking: ImGuiDockNode Tree manipulation functions
19531//-----------------------------------------------------------------------------
19532// - DockNodeTreeSplit()
19533// - DockNodeTreeMerge()
19534// - DockNodeTreeUpdatePosSize()
19535// - DockNodeTreeUpdateSplitterFindTouchingNode()
19536// - DockNodeTreeUpdateSplitter()
19537// - DockNodeTreeFindFallbackLeafNode()
19538// - DockNodeTreeFindNodeByPos()
19539//-----------------------------------------------------------------------------
19540
19541void ImGui::DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiAxis split_axis, int split_inheritor_child_idx, float split_ratio, ImGuiDockNode* new_node)
19542{
19543 ImGuiContext& g = *GImGui;
19544 IM_ASSERT(split_axis != ImGuiAxis_None);
19545
19546 ImGuiDockNode* child_0 = (new_node && split_inheritor_child_idx != 0) ? new_node : DockContextAddNode(ctx, 0);
19547 child_0->ParentNode = parent_node;
19548
19549 ImGuiDockNode* child_1 = (new_node && split_inheritor_child_idx != 1) ? new_node : DockContextAddNode(ctx, 0);
19550 child_1->ParentNode = parent_node;
19551
19552 ImGuiDockNode* child_inheritor = (split_inheritor_child_idx == 0) ? child_0 : child_1;
19553 DockNodeMoveChildNodes(child_inheritor, parent_node);
19554 parent_node->ChildNodes[0] = child_0;
19555 parent_node->ChildNodes[1] = child_1;
19556 parent_node->ChildNodes[split_inheritor_child_idx]->VisibleWindow = parent_node->VisibleWindow;
19557 parent_node->SplitAxis = split_axis;
19558 parent_node->VisibleWindow = NULL;
19559 parent_node->AuthorityForPos = parent_node->AuthorityForSize = ImGuiDataAuthority_DockNode;
19560
19561 float size_avail = (parent_node->Size[split_axis] - g.Style.DockingSeparatorSize);
19562 size_avail = ImMax(size_avail, g.Style.WindowMinSize[split_axis] * 2.0f);
19563 IM_ASSERT(size_avail > 0.0f); // If you created a node manually with DockBuilderAddNode(), you need to also call DockBuilderSetNodeSize() before splitting.
19564 child_0->SizeRef = child_1->SizeRef = parent_node->Size;
19565 child_0->SizeRef[split_axis] = ImTrunc(size_avail * split_ratio);
19566 child_1->SizeRef[split_axis] = ImTrunc(size_avail - child_0->SizeRef[split_axis]);
19567
19568 DockNodeMoveWindows(parent_node->ChildNodes[split_inheritor_child_idx], parent_node);
19569 DockSettingsRenameNodeReferences(parent_node->ID, parent_node->ChildNodes[split_inheritor_child_idx]->ID);
19571 DockNodeTreeUpdatePosSize(parent_node, parent_node->Pos, parent_node->Size);
19572
19573 // Flags transfer (e.g. this is where we transfer the ImGuiDockNodeFlags_CentralNode property)
19576 child_inheritor->LocalFlags = parent_node->LocalFlags & ImGuiDockNodeFlags_LocalFlagsTransferMask_;
19577 parent_node->LocalFlags &= ~ImGuiDockNodeFlags_LocalFlagsTransferMask_;
19578 child_0->UpdateMergedFlags();
19579 child_1->UpdateMergedFlags();
19580 parent_node->UpdateMergedFlags();
19581 if (child_inheritor->IsCentralNode())
19582 DockNodeGetRootNode(parent_node)->CentralNode = child_inheritor;
19583}
19584
19585void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiDockNode* merge_lead_child)
19586{
19587 // When called from DockContextProcessUndockNode() it is possible that one of the child is NULL.
19588 ImGuiContext& g = *GImGui;
19589 ImGuiDockNode* child_0 = parent_node->ChildNodes[0];
19590 ImGuiDockNode* child_1 = parent_node->ChildNodes[1];
19591 IM_ASSERT(child_0 || child_1);
19592 IM_ASSERT(merge_lead_child == child_0 || merge_lead_child == child_1);
19593 if ((child_0 && child_0->Windows.Size > 0) || (child_1 && child_1->Windows.Size > 0))
19594 {
19595 IM_ASSERT(parent_node->TabBar == NULL);
19596 IM_ASSERT(parent_node->Windows.Size == 0);
19597 }
19598 IMGUI_DEBUG_LOG_DOCKING("[docking] DockNodeTreeMerge: 0x%08X + 0x%08X back into parent 0x%08X\n", child_0 ? child_0->ID : 0, child_1 ? child_1->ID : 0, parent_node->ID);
19599
19600 ImVec2 backup_last_explicit_size = parent_node->SizeRef;
19601 DockNodeMoveChildNodes(parent_node, merge_lead_child);
19602 if (child_0)
19603 {
19604 DockNodeMoveWindows(parent_node, child_0); // Generally only 1 of the 2 child node will have windows
19605 DockSettingsRenameNodeReferences(child_0->ID, parent_node->ID);
19606 }
19607 if (child_1)
19608 {
19609 DockNodeMoveWindows(parent_node, child_1);
19610 DockSettingsRenameNodeReferences(child_1->ID, parent_node->ID);
19611 }
19612 DockNodeApplyPosSizeToWindows(parent_node);
19613 parent_node->AuthorityForPos = parent_node->AuthorityForSize = parent_node->AuthorityForViewport = ImGuiDataAuthority_Auto;
19614 parent_node->VisibleWindow = merge_lead_child->VisibleWindow;
19615 parent_node->SizeRef = backup_last_explicit_size;
19616
19617 // Flags transfer
19618 parent_node->LocalFlags &= ~ImGuiDockNodeFlags_LocalFlagsTransferMask_; // Preserve Dockspace flag
19619 parent_node->LocalFlags |= (child_0 ? child_0->LocalFlags : 0) & ImGuiDockNodeFlags_LocalFlagsTransferMask_;
19620 parent_node->LocalFlags |= (child_1 ? child_1->LocalFlags : 0) & ImGuiDockNodeFlags_LocalFlagsTransferMask_;
19621 parent_node->LocalFlagsInWindows = (child_0 ? child_0->LocalFlagsInWindows : 0) | (child_1 ? child_1->LocalFlagsInWindows : 0); // FIXME: Would be more consistent to update from actual windows
19622 parent_node->UpdateMergedFlags();
19623
19624 if (child_0)
19625 {
19626 ctx->DockContext.Nodes.SetVoidPtr(child_0->ID, NULL);
19627 IM_DELETE(child_0);
19628 }
19629 if (child_1)
19630 {
19631 ctx->DockContext.Nodes.SetVoidPtr(child_1->ID, NULL);
19632 IM_DELETE(child_1);
19633 }
19634}
19635
19636// Update Pos/Size for a node hierarchy (don't affect child Windows yet)
19637// (Depth-first, Pre-Order)
19638void ImGui::DockNodeTreeUpdatePosSize(ImGuiDockNode* node, ImVec2 pos, ImVec2 size, ImGuiDockNode* only_write_to_single_node)
19639{
19640 // During the regular dock node update we write to all nodes.
19641 // 'only_write_to_single_node' is only set when turning a node visible mid-frame and we need its size right-away.
19642 ImGuiContext& g = *GImGui;
19643 const bool write_to_node = only_write_to_single_node == NULL || only_write_to_single_node == node;
19644 if (write_to_node)
19645 {
19646 node->Pos = pos;
19647 node->Size = size;
19648 }
19649
19650 if (node->IsLeafNode())
19651 return;
19652
19653 ImGuiDockNode* child_0 = node->ChildNodes[0];
19654 ImGuiDockNode* child_1 = node->ChildNodes[1];
19655 ImVec2 child_0_pos = pos, child_1_pos = pos;
19656 ImVec2 child_0_size = size, child_1_size = size;
19657
19658 const bool child_0_is_toward_single_node = (only_write_to_single_node != NULL && DockNodeIsInHierarchyOf(only_write_to_single_node, child_0));
19659 const bool child_1_is_toward_single_node = (only_write_to_single_node != NULL && DockNodeIsInHierarchyOf(only_write_to_single_node, child_1));
19660 const bool child_0_is_or_will_be_visible = child_0->IsVisible || child_0_is_toward_single_node;
19661 const bool child_1_is_or_will_be_visible = child_1->IsVisible || child_1_is_toward_single_node;
19662
19663 if (child_0_is_or_will_be_visible && child_1_is_or_will_be_visible)
19664 {
19665 const float spacing = g.Style.DockingSeparatorSize;
19666 const ImGuiAxis axis = (ImGuiAxis)node->SplitAxis;
19667 const float size_avail = ImMax(size[axis] - spacing, 0.0f);
19668
19669 // Size allocation policy
19670 // 1) The first 0..WindowMinSize[axis]*2 are allocated evenly to both windows.
19671 const float size_min_each = ImTrunc(ImMin(size_avail, g.Style.WindowMinSize[axis] * 2.0f) * 0.5f);
19672
19673 // FIXME: Blocks 2) and 3) are essentially doing nearly the same thing.
19674 // Difference are: write-back to SizeRef; application of a minimum size; rounding before ImTrunc()
19675 // Clarify and rework differences between Size & SizeRef and purpose of WantLockSizeOnce
19676
19677 // 2) Process locked absolute size (during a splitter resize we preserve the child of nodes not touching the splitter edge)
19678 if (child_0->WantLockSizeOnce && !child_1->WantLockSizeOnce)
19679 {
19680 child_0_size[axis] = child_0->SizeRef[axis] = ImMin(size_avail - 1.0f, child_0->Size[axis]);
19681 child_1_size[axis] = child_1->SizeRef[axis] = (size_avail - child_0_size[axis]);
19682 IM_ASSERT(child_0->SizeRef[axis] > 0.0f && child_1->SizeRef[axis] > 0.0f);
19683 }
19684 else if (child_1->WantLockSizeOnce && !child_0->WantLockSizeOnce)
19685 {
19686 child_1_size[axis] = child_1->SizeRef[axis] = ImMin(size_avail - 1.0f, child_1->Size[axis]);
19687 child_0_size[axis] = child_0->SizeRef[axis] = (size_avail - child_1_size[axis]);
19688 IM_ASSERT(child_0->SizeRef[axis] > 0.0f && child_1->SizeRef[axis] > 0.0f);
19689 }
19690 else if (child_0->WantLockSizeOnce && child_1->WantLockSizeOnce)
19691 {
19692 // FIXME-DOCK: We cannot honor the requested size, so apply ratio.
19693 // Currently this path will only be taken if code programmatically sets WantLockSizeOnce
19694 float split_ratio = child_0_size[axis] / (child_0_size[axis] + child_1_size[axis]);
19695 child_0_size[axis] = child_0->SizeRef[axis] = ImTrunc(size_avail * split_ratio);
19696 child_1_size[axis] = child_1->SizeRef[axis] = (size_avail - child_0_size[axis]);
19697 IM_ASSERT(child_0->SizeRef[axis] > 0.0f && child_1->SizeRef[axis] > 0.0f);
19698 }
19699
19700 // 3) If one window is the central node (~ use remaining space, should be made explicit!), use explicit size from the other, and remainder for the central node
19701 else if (child_0->SizeRef[axis] != 0.0f && child_1->HasCentralNodeChild)
19702 {
19703 child_0_size[axis] = ImMin(size_avail - size_min_each, child_0->SizeRef[axis]);
19704 child_1_size[axis] = (size_avail - child_0_size[axis]);
19705 }
19706 else if (child_1->SizeRef[axis] != 0.0f && child_0->HasCentralNodeChild)
19707 {
19708 child_1_size[axis] = ImMin(size_avail - size_min_each, child_1->SizeRef[axis]);
19709 child_0_size[axis] = (size_avail - child_1_size[axis]);
19710 }
19711 else
19712 {
19713 // 4) Otherwise distribute according to the relative ratio of each SizeRef value
19714 float split_ratio = child_0->SizeRef[axis] / (child_0->SizeRef[axis] + child_1->SizeRef[axis]);
19715 child_0_size[axis] = ImMax(size_min_each, ImTrunc(size_avail * split_ratio + 0.5f));
19716 child_1_size[axis] = (size_avail - child_0_size[axis]);
19717 }
19718
19719 child_1_pos[axis] += spacing + child_0_size[axis];
19720 }
19721
19722 if (only_write_to_single_node == NULL)
19723 child_0->WantLockSizeOnce = child_1->WantLockSizeOnce = false;
19724
19725 const bool child_0_recurse = only_write_to_single_node ? child_0_is_toward_single_node : child_0->IsVisible;
19726 const bool child_1_recurse = only_write_to_single_node ? child_1_is_toward_single_node : child_1->IsVisible;
19727 if (child_0_recurse)
19728 DockNodeTreeUpdatePosSize(child_0, child_0_pos, child_0_size);
19729 if (child_1_recurse)
19730 DockNodeTreeUpdatePosSize(child_1, child_1_pos, child_1_size);
19731}
19732
19734{
19735 if (node->IsLeafNode())
19736 {
19737 touching_nodes->push_back(node);
19738 return;
19739 }
19740 if (node->ChildNodes[0]->IsVisible)
19741 if (node->SplitAxis != axis || side == 0 || !node->ChildNodes[1]->IsVisible)
19742 DockNodeTreeUpdateSplitterFindTouchingNode(node->ChildNodes[0], axis, side, touching_nodes);
19743 if (node->ChildNodes[1]->IsVisible)
19744 if (node->SplitAxis != axis || side == 1 || !node->ChildNodes[0]->IsVisible)
19745 DockNodeTreeUpdateSplitterFindTouchingNode(node->ChildNodes[1], axis, side, touching_nodes);
19746}
19747
19748// (Depth-First, Pre-Order)
19750{
19751 if (node->IsLeafNode())
19752 return;
19753
19754 ImGuiContext& g = *GImGui;
19755
19756 ImGuiDockNode* child_0 = node->ChildNodes[0];
19757 ImGuiDockNode* child_1 = node->ChildNodes[1];
19758 if (child_0->IsVisible && child_1->IsVisible)
19759 {
19760 // Bounding box of the splitter cover the space between both nodes (w = Spacing, h = Size[xy^1] for when splitting horizontally)
19761 const ImGuiAxis axis = (ImGuiAxis)node->SplitAxis;
19762 IM_ASSERT(axis != ImGuiAxis_None);
19763 ImRect bb;
19764 bb.Min = child_0->Pos;
19765 bb.Max = child_1->Pos;
19766 bb.Min[axis] += child_0->Size[axis];
19767 bb.Max[axis ^ 1] += child_1->Size[axis ^ 1];
19768 //if (g.IO.KeyCtrl) GetForegroundDrawList(g.CurrentWindow->Viewport)->AddRect(bb.Min, bb.Max, IM_COL32(255,0,255,255));
19769
19770 const ImGuiDockNodeFlags merged_flags = child_0->MergedFlags | child_1->MergedFlags; // Merged flags for BOTH childs
19772 if ((merged_flags & ImGuiDockNodeFlags_NoResize) || (merged_flags & no_resize_axis_flag))
19773 {
19774 ImGuiWindow* window = g.CurrentWindow;
19776 }
19777 else
19778 {
19779 //bb.Min[axis] += 1; // Display a little inward so highlight doesn't connect with nearby tabs on the neighbor node.
19780 //bb.Max[axis] -= 1;
19781 PushID(node->ID);
19782
19783 // Find resizing limits by gathering list of nodes that are touching the splitter line.
19784 ImVector<ImGuiDockNode*> touching_nodes[2];
19785 float min_size = g.Style.WindowMinSize[axis];
19786 float resize_limits[2];
19787 resize_limits[0] = node->ChildNodes[0]->Pos[axis] + min_size;
19788 resize_limits[1] = node->ChildNodes[1]->Pos[axis] + node->ChildNodes[1]->Size[axis] - min_size;
19789
19790 ImGuiID splitter_id = GetID("##Splitter");
19791 if (g.ActiveId == splitter_id) // Only process when splitter is active
19792 {
19793 DockNodeTreeUpdateSplitterFindTouchingNode(child_0, axis, 1, &touching_nodes[0]);
19794 DockNodeTreeUpdateSplitterFindTouchingNode(child_1, axis, 0, &touching_nodes[1]);
19795 for (int touching_node_n = 0; touching_node_n < touching_nodes[0].Size; touching_node_n++)
19796 resize_limits[0] = ImMax(resize_limits[0], touching_nodes[0][touching_node_n]->Rect().Min[axis] + min_size);
19797 for (int touching_node_n = 0; touching_node_n < touching_nodes[1].Size; touching_node_n++)
19798 resize_limits[1] = ImMin(resize_limits[1], touching_nodes[1][touching_node_n]->Rect().Max[axis] - min_size);
19799
19800 // [DEBUG] Render touching nodes & limits
19801 /*
19802 ImDrawList* draw_list = node->HostWindow ? GetForegroundDrawList(node->HostWindow) : GetForegroundDrawList(GetMainViewport());
19803 for (int n = 0; n < 2; n++)
19804 {
19805 for (int touching_node_n = 0; touching_node_n < touching_nodes[n].Size; touching_node_n++)
19806 draw_list->AddRect(touching_nodes[n][touching_node_n]->Pos, touching_nodes[n][touching_node_n]->Pos + touching_nodes[n][touching_node_n]->Size, IM_COL32(0, 255, 0, 255));
19807 if (axis == ImGuiAxis_X)
19808 draw_list->AddLine(ImVec2(resize_limits[n], node->ChildNodes[n]->Pos.y), ImVec2(resize_limits[n], node->ChildNodes[n]->Pos.y + node->ChildNodes[n]->Size.y), IM_COL32(255, 0, 255, 255), 3.0f);
19809 else
19810 draw_list->AddLine(ImVec2(node->ChildNodes[n]->Pos.x, resize_limits[n]), ImVec2(node->ChildNodes[n]->Pos.x + node->ChildNodes[n]->Size.x, resize_limits[n]), IM_COL32(255, 0, 255, 255), 3.0f);
19811 }
19812 */
19813 }
19814
19815 // Use a short delay before highlighting the splitter (and changing the mouse cursor) in order for regular mouse movement to not highlight many splitters
19816 float cur_size_0 = child_0->Size[axis];
19817 float cur_size_1 = child_1->Size[axis];
19818 float min_size_0 = resize_limits[0] - child_0->Pos[axis];
19819 float min_size_1 = child_1->Pos[axis] + child_1->Size[axis] - resize_limits[1];
19821 if (SplitterBehavior(bb, GetID("##Splitter"), axis, &cur_size_0, &cur_size_1, min_size_0, min_size_1, g.WindowsBorderHoverPadding, WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER, bg_col))
19822 {
19823 if (touching_nodes[0].Size > 0 && touching_nodes[1].Size > 0)
19824 {
19825 child_0->Size[axis] = child_0->SizeRef[axis] = cur_size_0;
19826 child_1->Pos[axis] -= cur_size_1 - child_1->Size[axis];
19827 child_1->Size[axis] = child_1->SizeRef[axis] = cur_size_1;
19828
19829 // Lock the size of every node that is a sibling of the node we are touching
19830 // This might be less desirable if we can merge sibling of a same axis into the same parental level.
19831 for (int side_n = 0; side_n < 2; side_n++)
19832 for (int touching_node_n = 0; touching_node_n < touching_nodes[side_n].Size; touching_node_n++)
19833 {
19834 ImGuiDockNode* touching_node = touching_nodes[side_n][touching_node_n];
19835 //ImDrawList* draw_list = node->HostWindow ? GetForegroundDrawList(node->HostWindow) : GetForegroundDrawList(GetMainViewport());
19836 //draw_list->AddRect(touching_node->Pos, touching_node->Pos + touching_node->Size, IM_COL32(255, 128, 0, 255));
19837 while (touching_node->ParentNode != node)
19838 {
19839 if (touching_node->ParentNode->SplitAxis == axis)
19840 {
19841 // Mark other node so its size will be preserved during the upcoming call to DockNodeTreeUpdatePosSize().
19842 ImGuiDockNode* node_to_preserve = touching_node->ParentNode->ChildNodes[side_n];
19843 node_to_preserve->WantLockSizeOnce = true;
19844 //draw_list->AddRect(touching_node->Pos, touching_node->Rect().Max, IM_COL32(255, 0, 0, 255));
19845 //draw_list->AddRectFilled(node_to_preserve->Pos, node_to_preserve->Rect().Max, IM_COL32(0, 255, 0, 100));
19846 }
19847 touching_node = touching_node->ParentNode;
19848 }
19849 }
19850
19851 DockNodeTreeUpdatePosSize(child_0, child_0->Pos, child_0->Size);
19852 DockNodeTreeUpdatePosSize(child_1, child_1->Pos, child_1->Size);
19854 }
19855 }
19856 PopID();
19857 }
19858 }
19859
19860 if (child_0->IsVisible)
19862 if (child_1->IsVisible)
19864}
19865
19867{
19868 if (node->IsLeafNode())
19869 return node;
19871 return leaf_node;
19873 return leaf_node;
19874 return NULL;
19875}
19876
19878{
19879 if (!node->IsVisible)
19880 return NULL;
19881
19882 const float dock_spacing = 0.0f;// g.Style.ItemInnerSpacing.x; // FIXME: Relation to DOCKING_SPLITTER_SIZE?
19883 ImRect r(node->Pos, node->Pos + node->Size);
19884 r.Expand(dock_spacing * 0.5f);
19885 bool inside = r.Contains(pos);
19886 if (!inside)
19887 return NULL;
19888
19889 if (node->IsLeafNode())
19890 return node;
19891 if (ImGuiDockNode* hovered_node = DockNodeTreeFindVisibleNodeByPos(node->ChildNodes[0], pos))
19892 return hovered_node;
19893 if (ImGuiDockNode* hovered_node = DockNodeTreeFindVisibleNodeByPos(node->ChildNodes[1], pos))
19894 return hovered_node;
19895
19896 // This means we are hovering over the splitter/spacing of a parent node
19897 return node;
19898}
19899
19900//-----------------------------------------------------------------------------
19901// Docking: Public Functions (SetWindowDock, DockSpace, DockSpaceOverViewport)
19902//-----------------------------------------------------------------------------
19903// - SetWindowDock() [Internal]
19904// - DockSpace()
19905// - DockSpaceOverViewport()
19906//-----------------------------------------------------------------------------
19907
19908// [Internal] Called via SetNextWindowDockID()
19910{
19911 // Test condition (NB: bit 0 is always true) and clear flags for next time
19912 if (cond && (window->SetWindowDockAllowFlags & cond) == 0)
19913 return;
19915
19916 if (window->DockId == dock_id)
19917 return;
19918
19919 // If the user attempt to set a dock id that is a split node, we'll dig within to find a suitable docking spot
19920 ImGuiContext& g = *GImGui;
19921 if (ImGuiDockNode* new_node = DockContextFindNodeByID(&g, dock_id))
19922 if (new_node->IsSplitNode())
19923 {
19924 // Policy: Find central node or latest focused node. We first move back to our root node.
19925 new_node = DockNodeGetRootNode(new_node);
19926 if (new_node->CentralNode)
19927 {
19928 IM_ASSERT(new_node->CentralNode->IsCentralNode());
19929 dock_id = new_node->CentralNode->ID;
19930 }
19931 else
19932 {
19933 dock_id = new_node->LastFocusedNodeId;
19934 }
19935 }
19936
19937 if (window->DockId == dock_id)
19938 return;
19939
19940 if (window->DockNode)
19941 DockNodeRemoveWindow(window->DockNode, window, 0);
19942 window->DockId = dock_id;
19943}
19944
19945// Create an explicit dockspace node within an existing window. Also expose dock node flags and creates a CentralNode by default.
19946// The Central Node is always displayed even when empty and shrink/extend according to the requested size of its neighbors.
19947// DockSpace() needs to be submitted _before_ any window they can host. If you use a dockspace, submit it early in your app.
19948// When ImGuiDockNodeFlags_KeepAliveOnly is set, nothing is submitted in the current window (function may be called from any location).
19949ImGuiID ImGui::DockSpace(ImGuiID dockspace_id, const ImVec2& size_arg, ImGuiDockNodeFlags flags, const ImGuiWindowClass* window_class)
19950{
19951 ImGuiContext& g = *GImGui;
19954 return 0;
19955
19956 // Early out if parent window is hidden/collapsed
19957 // This is faster but also DockNodeUpdateTabBar() relies on TabBarLayout() running (which won't if SkipItems=true) to set NextSelectedTabId = 0). See #2960.
19958 // If for whichever reason this is causing problem we would need to ensure that DockNodeUpdateTabBar() ends up clearing NextSelectedTabId even if SkipItems=true.
19959 if (window->SkipItems)
19961 if ((flags & ImGuiDockNodeFlags_KeepAliveOnly) == 0)
19962 window = GetCurrentWindow(); // call to set window->WriteAccessed = true;
19963
19964 IM_ASSERT((flags & ImGuiDockNodeFlags_DockSpace) == 0); // Flag is automatically set by DockSpace() as LocalFlags, not SharedFlags!
19965 IM_ASSERT((flags & ImGuiDockNodeFlags_CentralNode) == 0); // Flag is automatically set by DockSpace() as LocalFlags, not SharedFlags! (#8145)
19966
19967 IM_ASSERT(dockspace_id != 0);
19968 ImGuiDockNode* node = DockContextFindNodeByID(&g, dockspace_id);
19969 if (node == NULL)
19970 {
19971 IMGUI_DEBUG_LOG_DOCKING("[docking] DockSpace: dockspace node 0x%08X created\n", dockspace_id);
19972 node = DockContextAddNode(&g, dockspace_id);
19974 }
19975 if (window_class && window_class->ClassId != node->WindowClass.ClassId)
19976 IMGUI_DEBUG_LOG_DOCKING("[docking] DockSpace: dockspace node 0x%08X: setup WindowClass 0x%08X -> 0x%08X\n", dockspace_id, node->WindowClass.ClassId, window_class->ClassId);
19977 node->SharedFlags = flags;
19978 node->WindowClass = window_class ? *window_class : ImGuiWindowClass();
19979
19980 // When a DockSpace transitioned form implicit to explicit this may be called a second time
19981 // It is possible that the node has already been claimed by a docked window which appeared before the DockSpace() node, so we overwrite IsDockSpace again.
19982 if (node->LastFrameActive == g.FrameCount && !(flags & ImGuiDockNodeFlags_KeepAliveOnly))
19983 {
19984 IM_ASSERT(node->IsDockSpace() == false && "Cannot call DockSpace() twice a frame with the same ID");
19986 return dockspace_id;
19987 }
19989
19990 // Keep alive mode, this is allow windows docked into this node so stay docked even if they are not visible
19992 {
19993 node->LastFrameAlive = g.FrameCount;
19994 return dockspace_id;
19995 }
19996
19997 const ImVec2 content_avail = GetContentRegionAvail();
19998 ImVec2 size = ImTrunc(size_arg);
19999 if (size.x <= 0.0f)
20000 size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues)
20001 if (size.y <= 0.0f)
20002 size.y = ImMax(content_avail.y + size.y, 4.0f);
20003 IM_ASSERT(size.x > 0.0f && size.y > 0.0f);
20004
20005 node->Pos = window->DC.CursorPos;
20006 node->Size = node->SizeRef = size;
20007 SetNextWindowPos(node->Pos);
20008 SetNextWindowSize(node->Size);
20009 g.NextWindowData.PosUndock = false;
20010
20011 // FIXME-DOCK: Why do we need a child window to host a dockspace, could we host it in the existing window?
20012 // FIXME-DOCK: What is the reason for not simply calling BeginChild()? (OK to have a reason but should be commented)
20016 window_flags |= ImGuiWindowFlags_NoBackground;
20017
20018 char title[256];
20019 ImFormatString(title, IM_ARRAYSIZE(title), "%s/DockSpace_%08X", window->Name, dockspace_id);
20020
20022 Begin(title, NULL, window_flags);
20023 PopStyleVar();
20024
20025 ImGuiWindow* host_window = g.CurrentWindow;
20026 DockNodeSetupHostWindow(node, host_window);
20027 host_window->ChildId = window->GetID(title);
20028 node->OnlyNodeWithWindows = NULL;
20029
20030 IM_ASSERT(node->IsRootNode());
20031
20032 // We need to handle the rare case were a central node is missing.
20033 // This can happen if the node was first created manually with DockBuilderAddNode() but _without_ the ImGuiDockNodeFlags_Dockspace.
20034 // Doing it correctly would set the _CentralNode flags, which would then propagate according to subsequent split.
20035 // It would also be ambiguous to attempt to assign a central node while there are split nodes, so we wait until there's a single node remaining.
20036 // The specific sub-property of _CentralNode we are interested in recovering here is the "Don't delete when empty" property,
20037 // as it doesn't make sense for an empty dockspace to not have this property.
20038 if (node->IsLeafNode() && !node->IsCentralNode())
20040
20041 // Update the node
20042 DockNodeUpdate(node);
20043
20044 End();
20045
20046 ImRect bb(node->Pos, node->Pos + size);
20047 ItemSize(size);
20048 ItemAdd(bb, dockspace_id, NULL, ImGuiItemFlags_NoNav); // Not a nav point (could be, would need to draw the nav rect and replicate/refactor activation from BeginChild(), but seems like CTRL+Tab works better here?)
20049 if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && IsWindowChildOf(g.HoveredWindow, host_window, false, true)) // To fullfill IsItemHovered(), similar to EndChild()
20051
20052 return dockspace_id;
20053}
20054
20055// Tips: Use with ImGuiDockNodeFlags_PassthruCentralNode!
20056// The limitation with this call is that your window won't have a local menu bar, but you can also use BeginMainMenuBar().
20057// Even though we could pass window flags, it would also require the user to be able to call BeginMenuBar() somehow meaning we can't Begin/End in a single function.
20058// If you really want a menu bar inside the same window as the one hosting the dockspace, you will need to copy this code somewhere and tweak it.
20059ImGuiID ImGui::DockSpaceOverViewport(ImGuiID dockspace_id, const ImGuiViewport* viewport, ImGuiDockNodeFlags dockspace_flags, const ImGuiWindowClass* window_class)
20060{
20061 if (viewport == NULL)
20062 viewport = GetMainViewport();
20063
20064 // Submit a window filling the entire viewport
20065 SetNextWindowPos(viewport->WorkPos);
20066 SetNextWindowSize(viewport->WorkSize);
20067 SetNextWindowViewport(viewport->ID);
20068
20069 ImGuiWindowFlags host_window_flags = 0;
20072 if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
20073 host_window_flags |= ImGuiWindowFlags_NoBackground;
20074
20075 // FIXME-OPT: When using ImGuiDockNodeFlags_KeepAliveOnly with DockSpaceOverViewport() we might be able to spare submitting the window,
20076 // since DockSpace() with that flag doesn't need a window. We'd only need to compute the default ID accordingly.
20077 if (dockspace_flags & ImGuiDockNodeFlags_KeepAliveOnly)
20078 host_window_flags |= ImGuiWindowFlags_NoMouseInputs;
20079
20080 char label[32];
20081 ImFormatString(label, IM_ARRAYSIZE(label), "WindowOverViewport_%08X", viewport->ID);
20082
20086 Begin(label, NULL, host_window_flags);
20087 PopStyleVar(3);
20088
20089 // Submit the dockspace
20090 if (dockspace_id == 0)
20091 dockspace_id = GetID("DockSpace");
20092 DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags, window_class);
20093
20094 End();
20095
20096 return dockspace_id;
20097}
20098
20099//-----------------------------------------------------------------------------
20100// Docking: Builder Functions
20101//-----------------------------------------------------------------------------
20102// Very early end-user API to manipulate dock nodes.
20103// Only available in imgui_internal.h. Expect this API to change/break!
20104// It is expected that those functions are all called _before_ the dockspace node submission.
20105//-----------------------------------------------------------------------------
20106// - DockBuilderDockWindow()
20107// - DockBuilderGetNode()
20108// - DockBuilderSetNodePos()
20109// - DockBuilderSetNodeSize()
20110// - DockBuilderAddNode()
20111// - DockBuilderRemoveNode()
20112// - DockBuilderRemoveNodeChildNodes()
20113// - DockBuilderRemoveNodeDockedWindows()
20114// - DockBuilderSplitNode()
20115// - DockBuilderCopyNodeRec()
20116// - DockBuilderCopyNode()
20117// - DockBuilderCopyWindowSettings()
20118// - DockBuilderCopyDockSpace()
20119// - DockBuilderFinish()
20120//-----------------------------------------------------------------------------
20121
20122void ImGui::DockBuilderDockWindow(const char* window_name, ImGuiID node_id)
20123{
20124 // We don't preserve relative order of multiple docked windows (by clearing DockOrder back to -1)
20125 ImGuiContext& g = *GImGui; IM_UNUSED(g);
20126 IMGUI_DEBUG_LOG_DOCKING("[docking] DockBuilderDockWindow '%s' to node 0x%08X\n", window_name, node_id);
20127 ImGuiID window_id = ImHashStr(window_name);
20128 if (ImGuiWindow* window = FindWindowByID(window_id))
20129 {
20130 // Apply to created window
20131 ImGuiID prev_node_id = window->DockId;
20132 SetWindowDock(window, node_id, ImGuiCond_Always);
20133 if (window->DockId != prev_node_id)
20134 window->DockOrder = -1;
20135 }
20136 else
20137 {
20138 // Apply to settings
20139 ImGuiWindowSettings* settings = FindWindowSettingsByID(window_id);
20140 if (settings == NULL)
20141 settings = CreateNewWindowSettings(window_name);
20142 if (settings->DockId != node_id)
20143 settings->DockOrder = -1;
20144 settings->DockId = node_id;
20145 }
20146}
20147
20149{
20150 ImGuiContext& g = *GImGui;
20151 return DockContextFindNodeByID(&g, node_id);
20152}
20153
20155{
20156 ImGuiContext& g = *GImGui;
20157 ImGuiDockNode* node = DockContextFindNodeByID(&g, node_id);
20158 if (node == NULL)
20159 return;
20160 node->Pos = pos;
20162}
20163
20165{
20166 ImGuiContext& g = *GImGui;
20167 ImGuiDockNode* node = DockContextFindNodeByID(&g, node_id);
20168 if (node == NULL)
20169 return;
20170 IM_ASSERT(size.x > 0.0f && size.y > 0.0f);
20171 node->Size = node->SizeRef = size;
20173}
20174
20175// Make sure to use the ImGuiDockNodeFlags_DockSpace flag to create a dockspace node! Otherwise this will create a floating node!
20176// - Floating node: you can then call DockBuilderSetNodePos()/DockBuilderSetNodeSize() to position and size the floating node.
20177// - Dockspace node: calling DockBuilderSetNodePos() is unnecessary.
20178// - If you intend to split a node immediately after creation using DockBuilderSplitNode(), make sure to call DockBuilderSetNodeSize() beforehand!
20179// For various reason, the splitting code currently needs a base size otherwise space may not be allocated as precisely as you would expect.
20180// - Use (id == 0) to let the system allocate a node identifier.
20181// - Existing node with a same id will be removed.
20183{
20184 ImGuiContext& g = *GImGui; IM_UNUSED(g);
20185 IMGUI_DEBUG_LOG_DOCKING("[docking] DockBuilderAddNode 0x%08X flags=%08X\n", node_id, flags);
20186
20187 if (node_id != 0)
20188 DockBuilderRemoveNode(node_id);
20189
20190 ImGuiDockNode* node = NULL;
20191 if (flags & ImGuiDockNodeFlags_DockSpace)
20192 {
20194 node = DockContextFindNodeByID(&g, node_id);
20195 }
20196 else
20197 {
20198 node = DockContextAddNode(&g, node_id);
20199 node->SetLocalFlags(flags);
20200 }
20201 node->LastFrameAlive = g.FrameCount; // Set this otherwise BeginDocked will undock during the same frame.
20202 return node->ID;
20203}
20204
20206{
20207 ImGuiContext& g = *GImGui; IM_UNUSED(g);
20208 IMGUI_DEBUG_LOG_DOCKING("[docking] DockBuilderRemoveNode 0x%08X\n", node_id);
20209
20210 ImGuiDockNode* node = DockContextFindNodeByID(&g, node_id);
20211 if (node == NULL)
20212 return;
20215 // Node may have moved or deleted if e.g. any merge happened
20216 node = DockContextFindNodeByID(&g, node_id);
20217 if (node == NULL)
20218 return;
20219 if (node->IsCentralNode() && node->ParentNode)
20221 DockContextRemoveNode(&g, node, true);
20222}
20223
20224// root_id = 0 to remove all, root_id != 0 to remove child of given node.
20226{
20227 ImGuiContext& g = *GImGui;
20229
20230 ImGuiDockNode* root_node = root_id ? DockContextFindNodeByID(&g, root_id) : NULL;
20231 if (root_id && root_node == NULL)
20232 return;
20233 bool has_central_node = false;
20234
20235 ImGuiDataAuthority backup_root_node_authority_for_pos = root_node ? root_node->AuthorityForPos : ImGuiDataAuthority_Auto;
20236 ImGuiDataAuthority backup_root_node_authority_for_size = root_node ? root_node->AuthorityForSize : ImGuiDataAuthority_Auto;
20237
20238 // Process active windows
20239 ImVector<ImGuiDockNode*> nodes_to_remove;
20240 for (int n = 0; n < dc->Nodes.Data.Size; n++)
20241 if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
20242 {
20243 bool want_removal = (root_id == 0) || (node->ID != root_id && DockNodeGetRootNode(node)->ID == root_id);
20244 if (want_removal)
20245 {
20246 if (node->IsCentralNode())
20247 has_central_node = true;
20248 if (root_id != 0)
20250 if (root_node)
20251 {
20252 DockNodeMoveWindows(root_node, node);
20253 DockSettingsRenameNodeReferences(node->ID, root_node->ID);
20254 }
20255 nodes_to_remove.push_back(node);
20256 }
20257 }
20258
20259 // DockNodeMoveWindows->DockNodeAddWindow will normally set those when reaching two windows (which is only adequate during interactive merge)
20260 // Make sure we don't lose our current pos/size. (FIXME-DOCK: Consider tidying up that code in DockNodeAddWindow instead)
20261 if (root_node)
20262 {
20263 root_node->AuthorityForPos = backup_root_node_authority_for_pos;
20264 root_node->AuthorityForSize = backup_root_node_authority_for_size;
20265 }
20266
20267 // Apply to settings
20268 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
20269 if (ImGuiID window_settings_dock_id = settings->DockId)
20270 for (int n = 0; n < nodes_to_remove.Size; n++)
20271 if (nodes_to_remove[n]->ID == window_settings_dock_id)
20272 {
20273 settings->DockId = root_id;
20274 break;
20275 }
20276
20277 // Not really efficient, but easier to destroy a whole hierarchy considering DockContextRemoveNode is attempting to merge nodes
20278 if (nodes_to_remove.Size > 1)
20279 ImQsort(nodes_to_remove.Data, nodes_to_remove.Size, sizeof(ImGuiDockNode*), DockNodeComparerDepthMostFirst);
20280 for (int n = 0; n < nodes_to_remove.Size; n++)
20281 DockContextRemoveNode(&g, nodes_to_remove[n], false);
20282
20283 if (root_id == 0)
20284 {
20285 dc->Nodes.Clear();
20286 dc->Requests.clear();
20287 }
20288 else if (has_central_node)
20289 {
20290 root_node->CentralNode = root_node;
20292 }
20293}
20294
20295void ImGui::DockBuilderRemoveNodeDockedWindows(ImGuiID root_id, bool clear_settings_refs)
20296{
20297 // Clear references in settings
20298 ImGuiContext& g = *GImGui;
20299 if (clear_settings_refs)
20300 {
20301 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
20302 {
20303 bool want_removal = (root_id == 0) || (settings->DockId == root_id);
20304 if (!want_removal && settings->DockId != 0)
20305 if (ImGuiDockNode* node = DockContextFindNodeByID(&g, settings->DockId))
20306 if (DockNodeGetRootNode(node)->ID == root_id)
20307 want_removal = true;
20308 if (want_removal)
20309 settings->DockId = 0;
20310 }
20311 }
20312
20313 // Clear references in windows
20314 for (int n = 0; n < g.Windows.Size; n++)
20315 {
20316 ImGuiWindow* window = g.Windows[n];
20317 bool want_removal = (root_id == 0) || (window->DockNode && DockNodeGetRootNode(window->DockNode)->ID == root_id) || (window->DockNodeAsHost && window->DockNodeAsHost->ID == root_id);
20318 if (want_removal)
20319 {
20320 const ImGuiID backup_dock_id = window->DockId;
20321 IM_UNUSED(backup_dock_id);
20322 DockContextProcessUndockWindow(&g, window, clear_settings_refs);
20323 if (!clear_settings_refs)
20324 IM_ASSERT(window->DockId == backup_dock_id);
20325 }
20326 }
20327}
20328
20329// If 'out_id_at_dir' or 'out_id_at_opposite_dir' are non NULL, the function will write out the ID of the two new nodes created.
20330// Return value is ID of the node at the specified direction, so same as (*out_id_at_dir) if that pointer is set.
20331// FIXME-DOCK: We are not exposing nor using split_outer.
20332ImGuiID ImGui::DockBuilderSplitNode(ImGuiID id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_at_dir, ImGuiID* out_id_at_opposite_dir)
20333{
20334 ImGuiContext& g = *GImGui;
20335 IM_ASSERT(split_dir != ImGuiDir_None);
20336 IMGUI_DEBUG_LOG_DOCKING("[docking] DockBuilderSplitNode: node 0x%08X, split_dir %d\n", id, split_dir);
20337
20338 ImGuiDockNode* node = DockContextFindNodeByID(&g, id);
20339 if (node == NULL)
20340 {
20341 IM_ASSERT(node != NULL);
20342 return 0;
20343 }
20344
20345 ImGuiDockRequest req;
20347 req.DockTargetWindow = NULL;
20348 req.DockTargetNode = node;
20349 req.DockPayload = NULL;
20350 req.DockSplitDir = split_dir;
20351 req.DockSplitRatio = ImSaturate((split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? size_ratio_for_node_at_dir : 1.0f - size_ratio_for_node_at_dir);
20352 req.DockSplitOuter = false;
20353 DockContextProcessDock(&g, &req);
20354
20355 ImGuiID id_at_dir = node->ChildNodes[(split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 0 : 1]->ID;
20356 ImGuiID id_at_opposite_dir = node->ChildNodes[(split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 1 : 0]->ID;
20357 if (out_id_at_dir)
20358 *out_id_at_dir = id_at_dir;
20359 if (out_id_at_opposite_dir)
20360 *out_id_at_opposite_dir = id_at_opposite_dir;
20361 return id_at_dir;
20362}
20363
20364static ImGuiDockNode* DockBuilderCopyNodeRec(ImGuiDockNode* src_node, ImGuiID dst_node_id_if_known, ImVector<ImGuiID>* out_node_remap_pairs)
20365{
20366 ImGuiContext& g = *GImGui;
20367 ImGuiDockNode* dst_node = ImGui::DockContextAddNode(&g, dst_node_id_if_known);
20368 dst_node->SharedFlags = src_node->SharedFlags;
20369 dst_node->LocalFlags = src_node->LocalFlags;
20371 dst_node->Pos = src_node->Pos;
20372 dst_node->Size = src_node->Size;
20373 dst_node->SizeRef = src_node->SizeRef;
20374 dst_node->SplitAxis = src_node->SplitAxis;
20375 dst_node->UpdateMergedFlags();
20376
20377 out_node_remap_pairs->push_back(src_node->ID);
20378 out_node_remap_pairs->push_back(dst_node->ID);
20379
20380 for (int child_n = 0; child_n < IM_ARRAYSIZE(src_node->ChildNodes); child_n++)
20381 if (src_node->ChildNodes[child_n])
20382 {
20383 dst_node->ChildNodes[child_n] = DockBuilderCopyNodeRec(src_node->ChildNodes[child_n], 0, out_node_remap_pairs);
20384 dst_node->ChildNodes[child_n]->ParentNode = dst_node;
20385 }
20386
20387 IMGUI_DEBUG_LOG_DOCKING("[docking] Fork node %08X -> %08X (%d childs)\n", src_node->ID, dst_node->ID, dst_node->IsSplitNode() ? 2 : 0);
20388 return dst_node;
20389}
20390
20391void ImGui::DockBuilderCopyNode(ImGuiID src_node_id, ImGuiID dst_node_id, ImVector<ImGuiID>* out_node_remap_pairs)
20392{
20393 ImGuiContext& g = *GImGui;
20394 IM_ASSERT(src_node_id != 0);
20395 IM_ASSERT(dst_node_id != 0);
20396 IM_ASSERT(out_node_remap_pairs != NULL);
20397
20398 DockBuilderRemoveNode(dst_node_id);
20399
20400 ImGuiDockNode* src_node = DockContextFindNodeByID(&g, src_node_id);
20401 IM_ASSERT(src_node != NULL);
20402
20403 out_node_remap_pairs->clear();
20404 DockBuilderCopyNodeRec(src_node, dst_node_id, out_node_remap_pairs);
20405
20406 IM_ASSERT((out_node_remap_pairs->Size % 2) == 0);
20407}
20408
20409void ImGui::DockBuilderCopyWindowSettings(const char* src_name, const char* dst_name)
20410{
20411 ImGuiWindow* src_window = FindWindowByName(src_name);
20412 if (src_window == NULL)
20413 return;
20414 if (ImGuiWindow* dst_window = FindWindowByName(dst_name))
20415 {
20416 dst_window->Pos = src_window->Pos;
20417 dst_window->Size = src_window->Size;
20418 dst_window->SizeFull = src_window->SizeFull;
20419 dst_window->Collapsed = src_window->Collapsed;
20420 }
20421 else
20422 {
20423 ImGuiWindowSettings* dst_settings = FindWindowSettingsByID(ImHashStr(dst_name));
20424 if (!dst_settings)
20425 dst_settings = CreateNewWindowSettings(dst_name);
20426 ImVec2ih window_pos_2ih = ImVec2ih(src_window->Pos);
20427 if (src_window->ViewportId != 0 && src_window->ViewportId != IMGUI_VIEWPORT_DEFAULT_ID)
20428 {
20429 dst_settings->ViewportPos = window_pos_2ih;
20430 dst_settings->ViewportId = src_window->ViewportId;
20431 dst_settings->Pos = ImVec2ih(0, 0);
20432 }
20433 else
20434 {
20435 dst_settings->Pos = window_pos_2ih;
20436 }
20437 dst_settings->Size = ImVec2ih(src_window->SizeFull);
20438 dst_settings->Collapsed = src_window->Collapsed;
20439 }
20440}
20441
20442// FIXME: Will probably want to change this signature, in particular how the window remapping pairs are passed.
20443void ImGui::DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_dockspace_id, ImVector<const char*>* in_window_remap_pairs)
20444{
20445 ImGuiContext& g = *GImGui;
20446 IM_ASSERT(src_dockspace_id != 0);
20447 IM_ASSERT(dst_dockspace_id != 0);
20448 IM_ASSERT(in_window_remap_pairs != NULL);
20449 IM_ASSERT((in_window_remap_pairs->Size % 2) == 0);
20450
20451 // Duplicate entire dock
20452 // FIXME: When overwriting dst_dockspace_id, windows that aren't part of our dockspace window class but that are docked in a same node will be split apart,
20453 // whereas we could attempt to at least keep them together in a new, same floating node.
20454 ImVector<ImGuiID> node_remap_pairs;
20455 DockBuilderCopyNode(src_dockspace_id, dst_dockspace_id, &node_remap_pairs);
20456
20457 // Attempt to transition all the upcoming windows associated to dst_dockspace_id into the newly created hierarchy of dock nodes
20458 // (The windows associated to src_dockspace_id are staying in place)
20459 ImVector<ImGuiID> src_windows;
20460 for (int remap_window_n = 0; remap_window_n < in_window_remap_pairs->Size; remap_window_n += 2)
20461 {
20462 const char* src_window_name = (*in_window_remap_pairs)[remap_window_n];
20463 const char* dst_window_name = (*in_window_remap_pairs)[remap_window_n + 1];
20464 ImGuiID src_window_id = ImHashStr(src_window_name);
20465 src_windows.push_back(src_window_id);
20466
20467 // Search in the remapping tables
20468 ImGuiID src_dock_id = 0;
20469 if (ImGuiWindow* src_window = FindWindowByID(src_window_id))
20470 src_dock_id = src_window->DockId;
20471 else if (ImGuiWindowSettings* src_window_settings = FindWindowSettingsByID(src_window_id))
20472 src_dock_id = src_window_settings->DockId;
20473 ImGuiID dst_dock_id = 0;
20474 for (int dock_remap_n = 0; dock_remap_n < node_remap_pairs.Size; dock_remap_n += 2)
20475 if (node_remap_pairs[dock_remap_n] == src_dock_id)
20476 {
20477 dst_dock_id = node_remap_pairs[dock_remap_n + 1];
20478 //node_remap_pairs[dock_remap_n] = node_remap_pairs[dock_remap_n + 1] = 0; // Clear
20479 break;
20480 }
20481
20482 if (dst_dock_id != 0)
20483 {
20484 // Docked windows gets redocked into the new node hierarchy.
20485 IMGUI_DEBUG_LOG_DOCKING("[docking] Remap live window '%s' 0x%08X -> '%s' 0x%08X\n", src_window_name, src_dock_id, dst_window_name, dst_dock_id);
20486 DockBuilderDockWindow(dst_window_name, dst_dock_id);
20487 }
20488 else
20489 {
20490 // Floating windows gets their settings transferred (regardless of whether the new window already exist or not)
20491 // When this is leading to a Copy and not a Move, we would get two overlapping floating windows. Could we possibly dock them together?
20492 IMGUI_DEBUG_LOG_DOCKING("[docking] Remap window settings '%s' -> '%s'\n", src_window_name, dst_window_name);
20493 DockBuilderCopyWindowSettings(src_window_name, dst_window_name);
20494 }
20495 }
20496
20497 // Anything else in the source nodes of 'node_remap_pairs' are windows that are not included in the remapping list.
20498 // Find those windows and move to them to the cloned dock node. This may be optional?
20499 // Dock those are a second step as undocking would invalidate source dock nodes.
20500 struct DockRemainingWindowTask { ImGuiWindow* Window; ImGuiID DockId; DockRemainingWindowTask(ImGuiWindow* window, ImGuiID dock_id) { Window = window; DockId = dock_id; } };
20501 ImVector<DockRemainingWindowTask> dock_remaining_windows;
20502 for (int dock_remap_n = 0; dock_remap_n < node_remap_pairs.Size; dock_remap_n += 2)
20503 if (ImGuiID src_dock_id = node_remap_pairs[dock_remap_n])
20504 {
20505 ImGuiID dst_dock_id = node_remap_pairs[dock_remap_n + 1];
20506 ImGuiDockNode* node = DockBuilderGetNode(src_dock_id);
20507 for (int window_n = 0; window_n < node->Windows.Size; window_n++)
20508 {
20509 ImGuiWindow* window = node->Windows[window_n];
20510 if (src_windows.contains(window->ID))
20511 continue;
20512
20513 // Docked windows gets redocked into the new node hierarchy.
20514 IMGUI_DEBUG_LOG_DOCKING("[docking] Remap window '%s' %08X -> %08X\n", window->Name, src_dock_id, dst_dock_id);
20515 dock_remaining_windows.push_back(DockRemainingWindowTask(window, dst_dock_id));
20516 }
20517 }
20518 for (const DockRemainingWindowTask& task : dock_remaining_windows)
20519 DockBuilderDockWindow(task.Window->Name, task.DockId);
20520}
20521
20522// FIXME-DOCK: This is awkward because in series of split user is likely to loose access to its root node.
20524{
20525 ImGuiContext& g = *GImGui;
20526 //DockContextRebuild(&g);
20528}
20529
20530//-----------------------------------------------------------------------------
20531// Docking: Begin/End Support Functions (called from Begin/End)
20532//-----------------------------------------------------------------------------
20533// - GetWindowAlwaysWantOwnTabBar()
20534// - DockContextBindNodeToWindow()
20535// - BeginDocked()
20536// - BeginDockableDragDropSource()
20537// - BeginDockableDragDropTarget()
20538//-----------------------------------------------------------------------------
20539
20541{
20542 ImGuiContext& g = *GImGui;
20545 if (!window->IsFallbackWindow) // We don't support AlwaysTabBar on the fallback/implicit window to avoid unused dock-node overhead/noise
20546 return true;
20547 return false;
20548}
20549
20551{
20552 ImGuiContext& g = *ctx;
20553 ImGuiDockNode* node = DockContextFindNodeByID(ctx, window->DockId);
20554 IM_ASSERT(window->DockNode == NULL);
20555
20556 // We should not be docking into a split node (SetWindowDock should avoid this)
20557 if (node && node->IsSplitNode())
20558 {
20559 DockContextProcessUndockWindow(ctx, window);
20560 return NULL;
20561 }
20562
20563 // Create node
20564 if (node == NULL)
20565 {
20566 node = DockContextAddNode(ctx, window->DockId);
20568 node->LastFrameAlive = g.FrameCount;
20569 }
20570
20571 // If the node just turned visible and is part of a hierarchy, it doesn't have a Size assigned by DockNodeTreeUpdatePosSize() yet,
20572 // so we're forcing a Pos/Size update from the first ancestor that is already visible (often it will be the root node).
20573 // If we don't do this, the window will be assigned a zero-size on its first frame, which won't ideally warm up the layout.
20574 // This is a little wonky because we don't normally update the Pos/Size of visible node mid-frame.
20575 if (!node->IsVisible)
20576 {
20577 ImGuiDockNode* ancestor_node = node;
20578 while (!ancestor_node->IsVisible && ancestor_node->ParentNode)
20579 ancestor_node = ancestor_node->ParentNode;
20580 IM_ASSERT(ancestor_node->Size.x > 0.0f && ancestor_node->Size.y > 0.0f);
20582 DockNodeTreeUpdatePosSize(ancestor_node, ancestor_node->Pos, ancestor_node->Size, node);
20583 }
20584
20585 // Add window to node
20586 bool node_was_visible = node->IsVisible;
20587 DockNodeAddWindow(node, window, true);
20588 node->IsVisible = node_was_visible; // Don't mark visible right away (so DockContextEndFrame() doesn't render it, maybe other side effects? will see)
20589 IM_ASSERT(node == window->DockNode);
20590 return node;
20591}
20592
20594{
20595 ImGuiContext& g = *GImGui;
20596 for (int color_n = 0; color_n < ImGuiWindowDockStyleCol_COUNT; color_n++)
20598}
20599
20600void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
20601{
20602 ImGuiContext& g = *GImGui;
20603
20604 // Clear fields ahead so most early-out paths don't have to do it
20605 window->DockIsActive = window->DockNodeIsVisible = window->DockTabIsVisible = false;
20606
20607 const bool auto_dock_node = GetWindowAlwaysWantOwnTabBar(window);
20608 if (auto_dock_node)
20609 {
20610 if (window->DockId == 0)
20611 {
20612 IM_ASSERT(window->DockNode == NULL);
20613 window->DockId = DockContextGenNodeID(&g);
20614 }
20615 }
20616 else
20617 {
20618 // Calling SetNextWindowPos() undock windows by default (by setting PosUndock)
20619 bool want_undock = false;
20620 want_undock |= (window->Flags & ImGuiWindowFlags_NoDocking) != 0;
20622 if (want_undock)
20623 {
20625 return;
20626 }
20627 }
20628
20629 // Bind to our dock node
20630 ImGuiDockNode* node = window->DockNode;
20631 if (node != NULL)
20632 IM_ASSERT(window->DockId == node->ID);
20633 if (window->DockId != 0 && node == NULL)
20634 {
20635 node = DockContextBindNodeToWindow(&g, window);
20636 if (node == NULL)
20637 return;
20638 }
20639
20640#if 0
20641 // Undock if the ImGuiDockNodeFlags_NoDockingInCentralNode got set
20642 if (node->IsCentralNode && (node->Flags & ImGuiDockNodeFlags_NoDockingInCentralNode))
20643 {
20644 DockContextProcessUndockWindow(ctx, window);
20645 return;
20646 }
20647#endif
20648
20649 // Undock if our dockspace node disappeared
20650 // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace node can be maintained alive while being inactive with ImGuiDockNodeFlags_KeepAliveOnly.
20651 if (node->LastFrameAlive < g.FrameCount)
20652 {
20653 // If the window has been orphaned, transition the docknode to an implicit node processed in DockContextNewFrameUpdateDocking()
20654 ImGuiDockNode* root_node = DockNodeGetRootNode(node);
20655 if (root_node->LastFrameAlive < g.FrameCount)
20657 else
20658 window->DockIsActive = true;
20659 return;
20660 }
20661
20662 // Store style overrides
20664
20665 // Fast path return. It is common for windows to hold on a persistent DockId but be the only visible window,
20666 // and never create neither a host window neither a tab bar.
20667 // FIXME-DOCK: replace ->HostWindow NULL compare with something more explicit (~was initially intended as a first frame test)
20668 if (node->HostWindow == NULL)
20669 {
20671 window->DockIsActive = true;
20672 if (node->Windows.Size > 1 && window->Appearing) // Only hide appearing window
20674 return;
20675 }
20676
20677 // We can have zero-sized nodes (e.g. children of a small-size dockspace)
20678 IM_ASSERT(node->HostWindow);
20679 IM_ASSERT(node->IsLeafNode());
20680 IM_ASSERT(node->Size.x >= 0.0f && node->Size.y >= 0.0f);
20682
20683 // Undock if we are submitted earlier than the host window
20685 {
20687 return;
20688 }
20689
20690 // Position/Size window
20691 SetNextWindowPos(node->Pos);
20692 SetNextWindowSize(node->Size);
20693 g.NextWindowData.PosUndock = false; // Cancel implicit undocking of SetNextWindowPos()
20694 window->DockIsActive = true;
20695 window->DockNodeIsVisible = true;
20696 window->DockTabIsVisible = false;
20698 return;
20699
20700 // When the window is selected we mark it as visible.
20701 if (node->VisibleWindow == window)
20702 window->DockTabIsVisible = true;
20703
20704 // Update window flag
20708 if (node->IsHiddenTabBar() || node->IsNoTabBar())
20710 else
20711 window->Flags &= ~ImGuiWindowFlags_NoTitleBar; // Clear the NoTitleBar flag in case the user set it: confusingly enough we need a title bar height so we are correctly offset, but it won't be displayed!
20712
20713 // Save new dock order only if the window has been visible once already
20714 // This allows multiple windows to be created in the same frame and have their respective dock orders preserved.
20715 if (node->TabBar && window->WasActive)
20716 window->DockOrder = (short)DockNodeGetTabOrder(window);
20717
20718 if ((node->WantCloseAll || node->WantCloseTabId == window->TabId) && p_open != NULL)
20719 *p_open = false;
20720
20721 // Update ChildId to allow returning from Child to Parent with Escape
20722 ImGuiWindow* parent_window = window->DockNode->HostWindow;
20723 window->ChildId = parent_window->GetID(window->Name);
20724}
20725
20727{
20728 ImGuiContext& g = *GImGui;
20729 IM_ASSERT(g.ActiveId == window->MoveId);
20730 IM_ASSERT(g.MovingWindow == window);
20731 IM_ASSERT(g.CurrentWindow == window);
20732
20733 // 0: Hold SHIFT to disable docking, 1: Hold SHIFT to enable docking.
20735 {
20736 // When ConfigDockingWithShift is set, display a tooltip to increase UI affordance.
20737 // We cannot set for HoveredWindowUnderMovingWindow != NULL here, as it is only valid/useful when drag and drop is already active
20738 // (because of the 'is_mouse_dragging_with_an_expected_destination' logic in UpdateViewportsNewFrame() function)
20740 if (g.IO.ConfigDockingWithShift && g.MouseStationaryTimer >= 1.0f && g.ActiveId >= 1.0f)
20742 return;
20743 }
20744
20745 g.LastItemData.ID = window->MoveId;
20746 window = window->RootWindowDockTree;
20747 IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0);
20748 bool is_drag_docking = (g.IO.ConfigDockingWithShift) || ImRect(0, 0, window->SizeFull.x, GetFrameHeight()).Contains(g.ActiveIdClickOffset); // FIXME-DOCKING: Need to make this stateful and explicit
20750 if (is_drag_docking && BeginDragDropSource(drag_drop_flags))
20751 {
20752 SetDragDropPayload(IMGUI_PAYLOAD_TYPE_WINDOW, &window, sizeof(window));
20754 StoreDockStyleForWindow(window); // Store style overrides while dragging (even when not docked) because docking preview may need it.
20755 }
20756}
20757
20759{
20760 ImGuiContext& g = *GImGui;
20761
20762 //IM_ASSERT(window->RootWindowDockTree == window); // May also be a DockSpace
20763 IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0);
20764 if (!g.DragDropActive)
20765 return;
20766 //GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
20767 if (!BeginDragDropTargetCustom(window->Rect(), window->ID))
20768 return;
20769
20770 // Peek into the payload before calling AcceptDragDropPayload() so we can handle overlapping dock nodes with filtering
20771 // (this is a little unusual pattern, normally most code would call AcceptDragDropPayload directly)
20772 const ImGuiPayload* payload = &g.DragDropPayload;
20773 if (!payload->IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW) || !DockNodeIsDropAllowed(window, *(ImGuiWindow**)payload->Data))
20774 {
20776 return;
20777 }
20778
20779 ImGuiWindow* payload_window = *(ImGuiWindow**)payload->Data;
20781 {
20782 // Select target node
20783 // (Important: we cannot use g.HoveredDockNode here! Because each of our target node have filters based on payload, each candidate drop target will do its own evaluation)
20784 bool dock_into_floating_window = false;
20785 ImGuiDockNode* node = NULL;
20786 if (window->DockNodeAsHost)
20787 {
20788 // Cannot assume that node will != NULL even though we passed the rectangle test: it depends on padding/spacing handled by DockNodeTreeFindVisibleNodeByPos().
20790
20791 // There is an edge case when docking into a dockspace which only has _inactive_ nodes (because none of the windows are active)
20792 // In this case we need to fallback into any leaf mode, possibly the central node.
20793 // FIXME-20181220: We should not have to test for IsLeafNode() here but we have another bug to fix first.
20794 if (node && node->IsDockSpace() && node->IsRootNode())
20795 node = (node->CentralNode && node->IsLeafNode()) ? node->CentralNode : DockNodeTreeFindFallbackLeafNode(node);
20796 }
20797 else
20798 {
20799 if (window->DockNode)
20800 node = window->DockNode;
20801 else
20802 dock_into_floating_window = true; // Dock into a regular window
20803 }
20804
20805 const ImRect explicit_target_rect = (node && node->TabBar && !node->IsHiddenTabBar() && !node->IsNoTabBar()) ? node->TabBar->BarRect : ImRect(window->Pos, window->Pos + ImVec2(window->Size.x, GetFrameHeight()));
20806 const bool is_explicit_target = g.IO.ConfigDockingWithShift || IsMouseHoveringRect(explicit_target_rect.Min, explicit_target_rect.Max);
20807
20808 // Preview docking request and find out split direction/ratio
20809 //const bool do_preview = true; // Ignore testing for payload->IsPreview() which removes one frame of delay, but breaks overlapping drop targets within the same window.
20810 const bool do_preview = payload->IsPreview() || payload->IsDelivery();
20811 if (do_preview && (node != NULL || dock_into_floating_window))
20812 {
20813 // If we have a non-leaf node it means we are hovering the border of a parent node, in which case only outer markers will appear.
20814 ImGuiDockPreviewData split_inner;
20815 ImGuiDockPreviewData split_outer;
20816 ImGuiDockPreviewData* split_data = &split_inner;
20817 if (node && (node->ParentNode || node->IsCentralNode() || !node->IsLeafNode()))
20818 if (ImGuiDockNode* root_node = DockNodeGetRootNode(node))
20819 {
20820 DockNodePreviewDockSetup(window, root_node, payload_window, NULL, &split_outer, is_explicit_target, true);
20821 if (split_outer.IsSplitDirExplicit)
20822 split_data = &split_outer;
20823 }
20824 if (!node || node->IsLeafNode())
20825 DockNodePreviewDockSetup(window, node, payload_window, NULL, &split_inner, is_explicit_target, false);
20826 if (split_data == &split_outer)
20827 split_inner.IsDropAllowed = false;
20828
20829 // Draw inner then outer, so that previewed tab (in inner data) will be behind the outer drop boxes
20830 DockNodePreviewDockRender(window, node, payload_window, &split_inner);
20831 DockNodePreviewDockRender(window, node, payload_window, &split_outer);
20832
20833 // Queue docking request
20834 if (split_data->IsDropAllowed && payload->IsDelivery())
20835 DockContextQueueDock(&g, window, split_data->SplitNode, payload_window, split_data->SplitDir, split_data->SplitRatio, split_data == &split_outer);
20836 }
20837 }
20839}
20840
20841//-----------------------------------------------------------------------------
20842// Docking: Settings
20843//-----------------------------------------------------------------------------
20844// - DockSettingsRenameNodeReferences()
20845// - DockSettingsRemoveNodeReferences()
20846// - DockSettingsFindNodeSettings()
20847// - DockSettingsHandler_ApplyAll()
20848// - DockSettingsHandler_ReadOpen()
20849// - DockSettingsHandler_ReadLine()
20850// - DockSettingsHandler_DockNodeToSettings()
20851// - DockSettingsHandler_WriteAll()
20852//-----------------------------------------------------------------------------
20853
20854static void ImGui::DockSettingsRenameNodeReferences(ImGuiID old_node_id, ImGuiID new_node_id)
20855{
20856 ImGuiContext& g = *GImGui;
20857 IMGUI_DEBUG_LOG_DOCKING("[docking] DockSettingsRenameNodeReferences: from 0x%08X -> to 0x%08X\n", old_node_id, new_node_id);
20858 for (int window_n = 0; window_n < g.Windows.Size; window_n++)
20859 {
20860 ImGuiWindow* window = g.Windows[window_n];
20861 if (window->DockId == old_node_id && window->DockNode == NULL)
20862 window->DockId = new_node_id;
20863 }
20865 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
20866 if (settings->DockId == old_node_id)
20867 settings->DockId = new_node_id;
20868}
20869
20870// Remove references stored in ImGuiWindowSettings to the given ImGuiDockNodeSettings
20871static void ImGui::DockSettingsRemoveNodeReferences(ImGuiID* node_ids, int node_ids_count)
20872{
20873 ImGuiContext& g = *GImGui;
20874 int found = 0;
20876 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
20877 for (int node_n = 0; node_n < node_ids_count; node_n++)
20878 if (settings->DockId == node_ids[node_n])
20879 {
20880 settings->DockId = 0;
20881 settings->DockOrder = -1;
20882 if (++found < node_ids_count)
20883 break;
20884 return;
20885 }
20886}
20887
20889{
20890 // FIXME-OPT
20891 ImGuiDockContext* dc = &ctx->DockContext;
20892 for (int n = 0; n < dc->NodesSettings.Size; n++)
20893 if (dc->NodesSettings[n].ID == id)
20894 return &dc->NodesSettings[n];
20895 return NULL;
20896}
20897
20898// Clear settings data
20900{
20901 ImGuiDockContext* dc = &ctx->DockContext;
20902 dc->NodesSettings.clear();
20903 DockContextClearNodes(ctx, 0, true);
20904}
20905
20906// Recreate nodes based on settings data
20908{
20909 // Prune settings at boot time only
20910 ImGuiDockContext* dc = &ctx->DockContext;
20911 if (ctx->Windows.Size == 0)
20915}
20916
20918{
20919 if (strcmp(name, "Data") != 0)
20920 return NULL;
20921 return (void*)1;
20922}
20923
20925{
20926 char c = 0;
20927 int x = 0, y = 0;
20928 int r = 0;
20929
20930 // Parsing, e.g.
20931 // " DockNode ID=0x00000001 Pos=383,193 Size=201,322 Split=Y,0.506 "
20932 // " DockNode ID=0x00000002 Parent=0x00000001 "
20933 // Important: this code expect currently fields in a fixed order.
20935 line = ImStrSkipBlank(line);
20936 if (strncmp(line, "DockNode", 8) == 0) { line = ImStrSkipBlank(line + strlen("DockNode")); }
20937 else if (strncmp(line, "DockSpace", 9) == 0) { line = ImStrSkipBlank(line + strlen("DockSpace")); node.Flags |= ImGuiDockNodeFlags_DockSpace; }
20938 else return;
20939 if (sscanf(line, "ID=0x%08X%n", &node.ID, &r) == 1) { line += r; } else return;
20940 if (sscanf(line, " Parent=0x%08X%n", &node.ParentNodeId, &r) == 1) { line += r; if (node.ParentNodeId == 0) return; }
20941 if (sscanf(line, " Window=0x%08X%n", &node.ParentWindowId, &r) ==1) { line += r; if (node.ParentWindowId == 0) return; }
20942 if (node.ParentNodeId == 0)
20943 {
20944 if (sscanf(line, " Pos=%i,%i%n", &x, &y, &r) == 2) { line += r; node.Pos = ImVec2ih((short)x, (short)y); } else return;
20945 if (sscanf(line, " Size=%i,%i%n", &x, &y, &r) == 2) { line += r; node.Size = ImVec2ih((short)x, (short)y); } else return;
20946 }
20947 else
20948 {
20949 if (sscanf(line, " SizeRef=%i,%i%n", &x, &y, &r) == 2) { line += r; node.SizeRef = ImVec2ih((short)x, (short)y); }
20950 }
20951 if (sscanf(line, " Split=%c%n", &c, &r) == 1) { line += r; if (c == 'X') node.SplitAxis = ImGuiAxis_X; else if (c == 'Y') node.SplitAxis = ImGuiAxis_Y; }
20952 if (sscanf(line, " NoResize=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_NoResize; }
20953 if (sscanf(line, " CentralNode=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_CentralNode; }
20954 if (sscanf(line, " NoTabBar=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_NoTabBar; }
20955 if (sscanf(line, " HiddenTabBar=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_HiddenTabBar; }
20956 if (sscanf(line, " NoWindowMenuButton=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_NoWindowMenuButton; }
20957 if (sscanf(line, " NoCloseButton=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_NoCloseButton; }
20958 if (sscanf(line, " Selected=0x%08X%n", &node.SelectedTabId,&r) == 1) { line += r; }
20959 if (node.ParentNodeId != 0)
20960 if (ImGuiDockNodeSettings* parent_settings = DockSettingsFindNodeSettings(ctx, node.ParentNodeId))
20961 node.Depth = parent_settings->Depth + 1;
20963}
20964
20966{
20967 ImGuiDockNodeSettings node_settings;
20968 IM_ASSERT(depth < (1 << (sizeof(node_settings.Depth) << 3)));
20969 node_settings.ID = node->ID;
20970 node_settings.ParentNodeId = node->ParentNode ? node->ParentNode->ID : 0;
20971 node_settings.ParentWindowId = (node->IsDockSpace() && node->HostWindow && node->HostWindow->ParentWindow) ? node->HostWindow->ParentWindow->ID : 0;
20972 node_settings.SelectedTabId = node->SelectedTabId;
20973 node_settings.SplitAxis = (signed char)(node->IsSplitNode() ? node->SplitAxis : ImGuiAxis_None);
20974 node_settings.Depth = (char)depth;
20975 node_settings.Flags = (node->LocalFlags & ImGuiDockNodeFlags_SavedFlagsMask_);
20976 node_settings.Pos = ImVec2ih(node->Pos);
20977 node_settings.Size = ImVec2ih(node->Size);
20978 node_settings.SizeRef = ImVec2ih(node->SizeRef);
20979 dc->NodesSettings.push_back(node_settings);
20980 if (node->ChildNodes[0])
20981 DockSettingsHandler_DockNodeToSettings(dc, node->ChildNodes[0], depth + 1);
20982 if (node->ChildNodes[1])
20983 DockSettingsHandler_DockNodeToSettings(dc, node->ChildNodes[1], depth + 1);
20984}
20985
20987{
20988 ImGuiContext& g = *ctx;
20989 ImGuiDockContext* dc = &ctx->DockContext;
20991 return;
20992
20993 // Gather settings data
20994 // (unlike our windows settings, because nodes are always built we can do a full rewrite of the SettingsNode buffer)
20995 dc->NodesSettings.resize(0);
20997 for (int n = 0; n < dc->Nodes.Data.Size; n++)
20998 if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
20999 if (node->IsRootNode())
21001
21002 int max_depth = 0;
21003 for (int node_n = 0; node_n < dc->NodesSettings.Size; node_n++)
21004 max_depth = ImMax((int)dc->NodesSettings[node_n].Depth, max_depth);
21005
21006 // Write to text buffer
21007 buf->appendf("[%s][Data]\n", handler->TypeName);
21008 for (int node_n = 0; node_n < dc->NodesSettings.Size; node_n++)
21009 {
21010 const int line_start_pos = buf->size(); (void)line_start_pos;
21011 const ImGuiDockNodeSettings* node_settings = &dc->NodesSettings[node_n];
21012 buf->appendf("%*s%s%*s", node_settings->Depth * 2, "", (node_settings->Flags & ImGuiDockNodeFlags_DockSpace) ? "DockSpace" : "DockNode ", (max_depth - node_settings->Depth) * 2, ""); // Text align nodes to facilitate looking at .ini file
21013 buf->appendf(" ID=0x%08X", node_settings->ID);
21014 if (node_settings->ParentNodeId)
21015 {
21016 buf->appendf(" Parent=0x%08X SizeRef=%d,%d", node_settings->ParentNodeId, node_settings->SizeRef.x, node_settings->SizeRef.y);
21017 }
21018 else
21019 {
21020 if (node_settings->ParentWindowId)
21021 buf->appendf(" Window=0x%08X", node_settings->ParentWindowId);
21022 buf->appendf(" Pos=%d,%d Size=%d,%d", node_settings->Pos.x, node_settings->Pos.y, node_settings->Size.x, node_settings->Size.y);
21023 }
21024 if (node_settings->SplitAxis != ImGuiAxis_None)
21025 buf->appendf(" Split=%c", (node_settings->SplitAxis == ImGuiAxis_X) ? 'X' : 'Y');
21026 if (node_settings->Flags & ImGuiDockNodeFlags_NoResize)
21027 buf->appendf(" NoResize=1");
21028 if (node_settings->Flags & ImGuiDockNodeFlags_CentralNode)
21029 buf->appendf(" CentralNode=1");
21030 if (node_settings->Flags & ImGuiDockNodeFlags_NoTabBar)
21031 buf->appendf(" NoTabBar=1");
21032 if (node_settings->Flags & ImGuiDockNodeFlags_HiddenTabBar)
21033 buf->appendf(" HiddenTabBar=1");
21034 if (node_settings->Flags & ImGuiDockNodeFlags_NoWindowMenuButton)
21035 buf->appendf(" NoWindowMenuButton=1");
21036 if (node_settings->Flags & ImGuiDockNodeFlags_NoCloseButton)
21037 buf->appendf(" NoCloseButton=1");
21038 if (node_settings->SelectedTabId)
21039 buf->appendf(" Selected=0x%08X", node_settings->SelectedTabId);
21040
21041 // [DEBUG] Include comments in the .ini file to ease debugging (this makes saving slower!)
21043 if (ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_settings->ID))
21044 {
21045 buf->appendf("%*s", ImMax(2, (line_start_pos + 92) - buf->size()), ""); // Align everything
21046 if (node->IsDockSpace() && node->HostWindow && node->HostWindow->ParentWindow)
21047 buf->appendf(" ; in '%s'", node->HostWindow->ParentWindow->Name);
21048 // Iterate settings so we can give info about windows that didn't exist during the session.
21049 int contains_window = 0;
21050 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
21051 if (settings->DockId == node_settings->ID)
21052 {
21053 if (contains_window++ == 0)
21054 buf->appendf(" ; contains ");
21055 buf->appendf("'%s' ", settings->GetName());
21056 }
21057 }
21058
21059 buf->appendf("\n");
21060 }
21061 buf->appendf("\n");
21062}
21063
21064
21065//-----------------------------------------------------------------------------
21066// [SECTION] PLATFORM DEPENDENT HELPERS
21067//-----------------------------------------------------------------------------
21068// - Default clipboard handlers
21069// - Default shell function handlers
21070// - Default IME handlers
21071//-----------------------------------------------------------------------------
21072
21073#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
21074
21075#ifdef _MSC_VER
21076#pragma comment(lib, "user32")
21077#pragma comment(lib, "kernel32")
21078#endif
21079
21080// Win32 clipboard implementation
21081// We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown()
21083{
21084 ImGuiContext& g = *ctx;
21086 if (!::OpenClipboard(NULL))
21087 return NULL;
21088 HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
21089 if (wbuf_handle == NULL)
21090 {
21091 ::CloseClipboard();
21092 return NULL;
21093 }
21094 if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
21095 {
21096 int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL);
21097 g.ClipboardHandlerData.resize(buf_len);
21098 ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL);
21099 }
21100 ::GlobalUnlock(wbuf_handle);
21101 ::CloseClipboard();
21102 return g.ClipboardHandlerData.Data;
21103}
21104
21105static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* text)
21106{
21107 if (!::OpenClipboard(NULL))
21108 return;
21109 const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
21110 HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));
21111 if (wbuf_handle == NULL)
21112 {
21113 ::CloseClipboard();
21114 return;
21115 }
21116 WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);
21117 ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);
21118 ::GlobalUnlock(wbuf_handle);
21119 ::EmptyClipboard();
21120 if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)
21121 ::GlobalFree(wbuf_handle);
21122 ::CloseClipboard();
21123}
21124
21125#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS)
21126
21127#include <Carbon/Carbon.h> // Use old API to avoid need for separate .mm file
21128static PasteboardRef main_clipboard = 0;
21129
21130// OSX clipboard implementation
21131// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line!
21132static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* text)
21133{
21134 if (!main_clipboard)
21135 PasteboardCreate(kPasteboardClipboard, &main_clipboard);
21136 PasteboardClear(main_clipboard);
21137 CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, ImStrlen(text));
21138 if (cf_data)
21139 {
21140 PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0);
21141 CFRelease(cf_data);
21142 }
21143}
21144
21146{
21147 ImGuiContext& g = *ctx;
21148 if (!main_clipboard)
21149 PasteboardCreate(kPasteboardClipboard, &main_clipboard);
21150 PasteboardSynchronize(main_clipboard);
21151
21152 ItemCount item_count = 0;
21153 PasteboardGetItemCount(main_clipboard, &item_count);
21154 for (ItemCount i = 0; i < item_count; i++)
21155 {
21156 PasteboardItemID item_id = 0;
21157 PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);
21158 CFArrayRef flavor_type_array = 0;
21159 PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array);
21160 for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++)
21161 {
21162 CFDataRef cf_data;
21163 if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr)
21164 {
21166 int length = (int)CFDataGetLength(cf_data);
21167 g.ClipboardHandlerData.resize(length + 1);
21168 CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data);
21169 g.ClipboardHandlerData[length] = 0;
21170 CFRelease(cf_data);
21171 return g.ClipboardHandlerData.Data;
21172 }
21173 }
21174 }
21175 return NULL;
21176}
21177
21178#else
21179
21180// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers.
21182{
21183 ImGuiContext& g = *ctx;
21184 return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin();
21185}
21186
21188{
21189 ImGuiContext& g = *ctx;
21191 const char* text_end = text + ImStrlen(text);
21192 g.ClipboardHandlerData.resize((int)(text_end - text) + 1);
21193 memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text));
21194 g.ClipboardHandlerData[(int)(text_end - text)] = 0;
21195}
21196
21197#endif // Default clipboard handlers
21198
21199//-----------------------------------------------------------------------------
21200
21201#ifndef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
21202#if defined(__APPLE__) && TARGET_OS_IPHONE
21203#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
21204#endif
21205#if defined(__3DS__)
21206#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
21207#endif
21208#if defined(_WIN32) && defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
21209#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
21210#endif
21211#endif // #ifndef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
21212
21213#ifndef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
21214#ifdef _WIN32
21215#include <shellapi.h> // ShellExecuteA()
21216#ifdef _MSC_VER
21217#pragma comment(lib, "shell32")
21218#endif
21219static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char* path)
21220{
21221 const int path_wsize = ::MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
21222 ImVector<wchar_t> path_wbuf;
21223 path_wbuf.resize(path_wsize);
21224 ::MultiByteToWideChar(CP_UTF8, 0, path, -1, path_wbuf.Data, path_wsize);
21225 return (INT_PTR)::ShellExecuteW(NULL, L"open", path_wbuf.Data, NULL, NULL, SW_SHOWDEFAULT) > 32;
21226}
21227#else
21228#include <sys/wait.h>
21229#include <unistd.h>
21231{
21232#if defined(__APPLE__)
21233 const char* args[] { "open", "--", path, NULL };
21234#else
21235 const char* args[] { "xdg-open", path, NULL };
21236#endif
21237 pid_t pid = fork();
21238 if (pid < 0)
21239 return false;
21240 if (!pid)
21241 {
21242 execvp(args[0], const_cast<char **>(args));
21243 exit(-1);
21244 }
21245 else
21246 {
21247 int status;
21248 waitpid(pid, &status, 0);
21249 return WEXITSTATUS(status) == 0;
21250 }
21251}
21252#endif
21253#else
21254static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char*) { return false; }
21255#endif // Default shell handlers
21256
21257//-----------------------------------------------------------------------------
21258
21259// Win32 API IME support (for Asian languages, etc.)
21260#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
21261
21262#include <imm.h>
21263#ifdef _MSC_VER
21264#pragma comment(lib, "imm32")
21265#endif
21266
21268{
21269 // Notify OS Input Method Editor of text input position
21270 HWND hwnd = (HWND)viewport->PlatformHandleRaw;
21271 if (hwnd == 0)
21272 return;
21273
21274 //::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0);
21275 if (HIMC himc = ::ImmGetContext(hwnd))
21276 {
21277 COMPOSITIONFORM composition_form = {};
21278 composition_form.ptCurrentPos.x = (LONG)(data->InputPos.x - viewport->Pos.x);
21279 composition_form.ptCurrentPos.y = (LONG)(data->InputPos.y - viewport->Pos.y);
21280 composition_form.dwStyle = CFS_FORCE_POSITION;
21281 ::ImmSetCompositionWindow(himc, &composition_form);
21282 CANDIDATEFORM candidate_form = {};
21283 candidate_form.dwStyle = CFS_CANDIDATEPOS;
21284 candidate_form.ptCurrentPos.x = (LONG)(data->InputPos.x - viewport->Pos.x);
21285 candidate_form.ptCurrentPos.y = (LONG)(data->InputPos.y - viewport->Pos.y);
21286 ::ImmSetCandidateWindow(himc, &candidate_form);
21287 ::ImmReleaseContext(hwnd, himc);
21288 }
21289}
21290
21291#else
21292
21294
21295#endif // Default IME handlers
21296
21297//-----------------------------------------------------------------------------
21298// [SECTION] METRICS/DEBUGGER WINDOW
21299//-----------------------------------------------------------------------------
21300// - DebugRenderViewportThumbnail() [Internal]
21301// - RenderViewportsThumbnails() [Internal]
21302// - DebugTextEncoding()
21303// - MetricsHelpMarker() [Internal]
21304// - ShowFontAtlas() [Internal but called by Demo!]
21305// - DebugNodeTexture() [Internal]
21306// - ShowMetricsWindow()
21307// - DebugNodeColumns() [Internal]
21308// - DebugNodeDockNode() [Internal]
21309// - DebugNodeDrawList() [Internal]
21310// - DebugNodeDrawCmdShowMeshAndBoundingBox() [Internal]
21311// - DebugNodeFont() [Internal]
21312// - DebugNodeFontGlyph() [Internal]
21313// - DebugNodeStorage() [Internal]
21314// - DebugNodeTabBar() [Internal]
21315// - DebugNodeViewport() [Internal]
21316// - DebugNodeWindow() [Internal]
21317// - DebugNodeWindowSettings() [Internal]
21318// - DebugNodeWindowsList() [Internal]
21319// - DebugNodeWindowsListByBeginStackParent() [Internal]
21320//-----------------------------------------------------------------------------
21321
21322#ifndef IMGUI_DISABLE_DEBUG_TOOLS
21323
21325{
21326 ImGuiContext& g = *GImGui;
21327 ImGuiWindow* window = g.CurrentWindow;
21328
21329 ImVec2 scale = bb.GetSize() / viewport->Size;
21330 ImVec2 off = bb.Min - viewport->Pos * scale;
21331 float alpha_mul = (viewport->Flags & ImGuiViewportFlags_IsMinimized) ? 0.30f : 1.00f;
21332 window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f));
21333 for (ImGuiWindow* thumb_window : g.Windows)
21334 {
21335 if (!thumb_window->WasActive || (thumb_window->Flags & ImGuiWindowFlags_ChildWindow))
21336 continue;
21337 if (thumb_window->Viewport != viewport)
21338 continue;
21339
21340 ImRect thumb_r = thumb_window->Rect();
21341 ImRect title_r = thumb_window->TitleBarRect();
21342 thumb_r = ImRect(ImTrunc(off + thumb_r.Min * scale), ImTrunc(off + thumb_r.Max * scale));
21343 title_r = ImRect(ImTrunc(off + title_r.Min * scale), ImTrunc(off + ImVec2(title_r.Max.x, title_r.Min.y + title_r.GetHeight() * 3.0f) * scale)); // Exaggerate title bar height
21344 thumb_r.ClipWithFull(bb);
21345 title_r.ClipWithFull(bb);
21346 const bool window_is_focused = (g.NavWindow && thumb_window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight);
21347 window->DrawList->AddRectFilled(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_WindowBg, alpha_mul));
21348 window->DrawList->AddRectFilled(title_r.Min, title_r.Max, GetColorU32(window_is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg, alpha_mul));
21349 window->DrawList->AddRect(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_Border, alpha_mul));
21350 window->DrawList->AddText(g.Font, g.FontSize * 1.0f, title_r.Min, GetColorU32(ImGuiCol_Text, alpha_mul), thumb_window->Name, FindRenderedTextEnd(thumb_window->Name));
21351 }
21352 draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul));
21353 if (viewport->ID == g.DebugMetricsConfig.HighlightViewportID)
21354 window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255));
21355}
21356
21358{
21359 ImGuiContext& g = *GImGui;
21360 ImGuiWindow* window = g.CurrentWindow;
21361
21362 // Draw monitor and calculate their boundaries
21363 float SCALE = 1.0f / 8.0f;
21364 ImRect bb_full(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
21365 for (ImGuiPlatformMonitor& monitor : g.PlatformIO.Monitors)
21366 bb_full.Add(ImRect(monitor.MainPos, monitor.MainPos + monitor.MainSize));
21367 ImVec2 p = window->DC.CursorPos;
21368 ImVec2 off = p - bb_full.Min * SCALE;
21369 for (ImGuiPlatformMonitor& monitor : g.PlatformIO.Monitors)
21370 {
21371 ImRect monitor_draw_bb(off + (monitor.MainPos) * SCALE, off + (monitor.MainPos + monitor.MainSize) * SCALE);
21372 window->DrawList->AddRect(monitor_draw_bb.Min, monitor_draw_bb.Max, (g.DebugMetricsConfig.HighlightMonitorIdx == g.PlatformIO.Monitors.index_from_ptr(&monitor)) ? IM_COL32(255, 255, 0, 255) : ImGui::GetColorU32(ImGuiCol_Border), 4.0f);
21373 window->DrawList->AddRectFilled(monitor_draw_bb.Min, monitor_draw_bb.Max, ImGui::GetColorU32(ImGuiCol_Border, 0.10f), 4.0f);
21374 }
21375
21376 // Draw viewports
21377 for (ImGuiViewportP* viewport : g.Viewports)
21378 {
21379 ImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE);
21380 ImGui::DebugRenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb);
21381 }
21382 ImGui::Dummy(bb_full.GetSize() * SCALE);
21383}
21384
21385static int IMGUI_CDECL ViewportComparerByLastFocusedStampCount(const void* lhs, const void* rhs)
21386{
21387 const ImGuiViewportP* a = *(const ImGuiViewportP* const*)lhs;
21388 const ImGuiViewportP* b = *(const ImGuiViewportP* const*)rhs;
21390}
21391
21392// Draw an arbitrary US keyboard layout to visualize translated keys
21394{
21395 const float scale = ImGui::GetFontSize() / 13.0f;
21396 const ImVec2 key_size = ImVec2(35.0f, 35.0f) * scale;
21397 const float key_rounding = 3.0f * scale;
21398 const ImVec2 key_face_size = ImVec2(25.0f, 25.0f) * scale;
21399 const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f) * scale;
21400 const float key_face_rounding = 2.0f * scale;
21401 const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f) * scale;
21402 const ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f);
21403 const float key_row_offset = 9.0f * scale;
21404
21405 ImVec2 board_min = GetCursorScreenPos();
21406 ImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f);
21407 ImVec2 start_pos = ImVec2(board_min.x + 5.0f - key_step.x, board_min.y);
21408
21409 struct KeyLayoutData { int Row, Col; const char* Label; ImGuiKey Key; };
21410 const KeyLayoutData keys_to_display[] =
21411 {
21412 { 0, 0, "", ImGuiKey_Tab }, { 0, 1, "Q", ImGuiKey_Q }, { 0, 2, "W", ImGuiKey_W }, { 0, 3, "E", ImGuiKey_E }, { 0, 4, "R", ImGuiKey_R },
21413 { 1, 0, "", ImGuiKey_CapsLock }, { 1, 1, "A", ImGuiKey_A }, { 1, 2, "S", ImGuiKey_S }, { 1, 3, "D", ImGuiKey_D }, { 1, 4, "F", ImGuiKey_F },
21414 { 2, 0, "", ImGuiKey_LeftShift },{ 2, 1, "Z", ImGuiKey_Z }, { 2, 2, "X", ImGuiKey_X }, { 2, 3, "C", ImGuiKey_C }, { 2, 4, "V", ImGuiKey_V }
21415 };
21416
21417 // Elements rendered manually via ImDrawList API are not clipped automatically.
21418 // While not strictly necessary, here IsItemVisible() is used to avoid rendering these shapes when they are out of view.
21419 Dummy(board_max - board_min);
21420 if (!IsItemVisible())
21421 return;
21422 draw_list->PushClipRect(board_min, board_max, true);
21423 for (int n = 0; n < IM_ARRAYSIZE(keys_to_display); n++)
21424 {
21425 const KeyLayoutData* key_data = &keys_to_display[n];
21426 ImVec2 key_min = ImVec2(start_pos.x + key_data->Col * key_step.x + key_data->Row * key_row_offset, start_pos.y + key_data->Row * key_step.y);
21427 ImVec2 key_max = key_min + key_size;
21428 draw_list->AddRectFilled(key_min, key_max, IM_COL32(204, 204, 204, 255), key_rounding);
21429 draw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding);
21430 ImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y);
21431 ImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y);
21432 draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f);
21433 draw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding);
21434 ImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y);
21435 draw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label);
21436 if (IsKeyDown(key_data->Key))
21437 draw_list->AddRectFilled(key_min, key_max, IM_COL32(255, 0, 0, 128), key_rounding);
21438 }
21439 draw_list->PopClipRect();
21440}
21441
21442// Helper tool to diagnose between text encoding issues and font loading issues. Pass your UTF-8 string and verify that there are correct.
21443void ImGui::DebugTextEncoding(const char* str)
21444{
21445 Text("Text: \"%s\"", str);
21447 return;
21448 TableSetupColumn("Offset");
21449 TableSetupColumn("UTF-8");
21450 TableSetupColumn("Glyph");
21451 TableSetupColumn("Codepoint");
21453 for (const char* p = str; *p != 0; )
21454 {
21455 unsigned int c;
21456 const int c_utf8_len = ImTextCharFromUtf8(&c, p, NULL);
21458 Text("%d", (int)(p - str));
21460 for (int byte_index = 0; byte_index < c_utf8_len; byte_index++)
21461 {
21462 if (byte_index > 0)
21463 SameLine();
21464 Text("0x%02X", (int)(unsigned char)p[byte_index]);
21465 }
21467 TextUnformatted(p, p + c_utf8_len);
21468 if (!GetFont()->IsGlyphInFont((ImWchar)c))
21469 {
21470 SameLine();
21471 TextUnformatted("[missing]");
21472 }
21474 Text("U+%04X", (int)c);
21475 p += c_utf8_len;
21476 }
21477 EndTable();
21478}
21479
21481{
21482 ImGuiContext& g = *GImGui;
21486}
21487
21488// Flash a given style color for some + inhibit modifications of this color via PushStyleColor() calls.
21490{
21491 ImGuiContext& g = *GImGui;
21493 g.DebugFlashStyleColorTime = 0.5f;
21496}
21497
21499{
21500 ImGuiContext& g = *GImGui;
21501 if (g.DebugFlashStyleColorTime <= 0.0f)
21502 return;
21505 if ((g.DebugFlashStyleColorTime -= g.IO.DeltaTime) <= 0.0f)
21507}
21508
21509static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, ImTextureID tex_id)
21510{
21511 union { void* ptr; int integer; } tex_id_opaque;
21512 memcpy(&tex_id_opaque, &tex_id, ImMin(sizeof(void*), sizeof(tex_id)));
21513 if (sizeof(tex_id) >= sizeof(void*))
21514 ImFormatString(buf, buf_size, "0x%p", tex_id_opaque.ptr);
21515 else
21516 ImFormatString(buf, buf_size, "0x%04X", tex_id_opaque.integer);
21517 return buf;
21518}
21519
21520static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, const ImDrawCmd* cmd)
21521{
21522 char* buf_end = buf + buf_size;
21523 if (cmd->TexRef._TexData != NULL)
21524 buf += ImFormatString(buf, buf_end - buf, "#%03d: ", cmd->TexRef._TexData->UniqueID);
21525 return FormatTextureIDForDebugDisplay(buf, (int)(buf_end - buf), cmd->TexRef.GetTexID()); // Calling TexRef::GetTexID() to avoid assert of cmd->GetTexID()
21526}
21527
21528// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds.
21529static void MetricsHelpMarker(const char* desc)
21530{
21531 ImGui::TextDisabled("(?)");
21533 {
21538 }
21539}
21540
21541#ifdef IMGUI_ENABLE_FREETYPE
21542namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetFontLoader(); IMGUI_API bool DebugEditFontLoaderFlags(unsigned int* p_font_builder_flags); }
21543#endif
21544
21545// [DEBUG] List fonts in a font atlas and display its texture
21547{
21548 ImGuiContext& g = *GImGui;
21549 ImGuiIO& io = g.IO;
21550 ImGuiStyle& style = g.Style;
21551
21552 BeginDisabled();
21553 CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures);
21554 EndDisabled();
21555 ShowFontSelector("Font");
21556 //BeginDisabled((io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0);
21557 if (DragFloat("FontSizeBase", &style.FontSizeBase, 0.20f, 5.0f, 100.0f, "%.0f"))
21558 style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work.
21559 SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize());
21560 SameLine(); MetricsHelpMarker("- This is scaling font only. General scaling will come later.");
21561 DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f);
21562 //BeginDisabled(io.ConfigDpiScaleFonts);
21563 DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 4.0f);
21564 //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten.");
21565 //EndDisabled();
21567 {
21568 BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!");
21569 BulletText("For instructions, see:");
21570 SameLine();
21571 TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md");
21572 }
21573 BulletText("Load a nice font for better results!");
21574 BulletText("Please submit feedback:");
21575 SameLine(); TextLinkOpenURL("#8465", "https://github.com/ocornut/imgui/issues/8465");
21576 BulletText("Read FAQ for more details:");
21577 SameLine(); TextLinkOpenURL("dearimgui.com/faq", "https://www.dearimgui.com/faq/");
21578 //EndDisabled();
21579
21580 SeparatorText("Font List");
21581
21583 Checkbox("Show font preview", &cfg->ShowFontPreview);
21584
21585 // Font loaders
21586 if (TreeNode("Loader", "Loader: \'%s\'", atlas->FontLoaderName ? atlas->FontLoaderName : "NULL"))
21587 {
21588 const ImFontLoader* loader_current = atlas->FontLoader;
21590#ifdef IMGUI_ENABLE_STB_TRUETYPE
21591 const ImFontLoader* loader_stbtruetype = ImFontAtlasGetFontLoaderForStbTruetype();
21592 if (RadioButton("stb_truetype", loader_current == loader_stbtruetype))
21593 atlas->SetFontLoader(loader_stbtruetype);
21594#else
21595 BeginDisabled();
21596 RadioButton("stb_truetype", false);
21597 SetItemTooltip("Requires #define IMGUI_ENABLE_STB_TRUETYPE");
21598 EndDisabled();
21599#endif
21600 SameLine();
21601#ifdef IMGUI_ENABLE_FREETYPE
21602 const ImFontLoader* loader_freetype = ImGuiFreeType::GetFontLoader();
21603 if (RadioButton("FreeType", loader_current == loader_freetype))
21604 atlas->SetFontLoader(loader_freetype);
21605 if (loader_current == loader_freetype)
21606 {
21607 unsigned int loader_flags = atlas->FontLoaderFlags;
21608 Text("Shared FreeType Loader Flags: 0x%08X", loader_flags);
21609 if (ImGuiFreeType::DebugEditFontLoaderFlags(&loader_flags))
21610 {
21611 for (ImFont* font : atlas->Fonts)
21612 ImFontAtlasFontDestroyOutput(atlas, font);
21613 atlas->FontLoaderFlags = loader_flags;
21614 for (ImFont* font : atlas->Fonts)
21615 ImFontAtlasFontInitOutput(atlas, font);
21616 }
21617 }
21618#else
21619 BeginDisabled();
21620 RadioButton("FreeType", false);
21621 SetItemTooltip("Requires #define IMGUI_ENABLE_FREETYPE + imgui_freetype.cpp.");
21622 EndDisabled();
21623#endif
21624 EndDisabled();
21625 TreePop();
21626 }
21627
21628 // Font list
21629 for (ImFont* font : atlas->Fonts)
21630 {
21631 PushID(font);
21632 DebugNodeFont(font);
21633 PopID();
21634 }
21635
21636 SeparatorText("Font Atlas");
21637 if (Button("Compact"))
21638 atlas->CompactCache();
21639 SameLine();
21640 if (Button("Grow"))
21642 SameLine();
21643 if (Button("Clear All"))
21644 ImFontAtlasBuildClear(atlas);
21645 SetItemTooltip("Destroy cache and custom rectangles.");
21646
21647 for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++)
21648 {
21649 ImTextureData* tex = atlas->TexList[tex_n];
21650 if (tex_n > 0)
21651 SameLine();
21652 Text("Tex: %dx%d", tex->Width, tex->Height);
21653 }
21654 const int packed_surface_sqrt = (int)sqrtf((float)atlas->Builder->RectsPackedSurface);
21655 const int discarded_surface_sqrt = (int)sqrtf((float)atlas->Builder->RectsDiscardedSurface);
21656 Text("Packed rects: %d, area: about %d px ~%dx%d px", atlas->Builder->RectsPackedCount, atlas->Builder->RectsPackedSurface, packed_surface_sqrt, packed_surface_sqrt);
21657 Text("incl. Discarded rects: %d, area: about %d px ~%dx%d px", atlas->Builder->RectsDiscardedCount, atlas->Builder->RectsDiscardedSurface, discarded_surface_sqrt, discarded_surface_sqrt);
21658
21660 if (TreeNode("Rects Index", "Rects Index (%d)", atlas->Builder->RectsPackedCount)) // <-- Use count of used rectangles
21661 {
21664 {
21665 for (const ImFontAtlasRectEntry& entry : atlas->Builder->RectsIndex)
21666 if (entry.IsUsed)
21667 {
21669 ImFontAtlasRect r = {};
21670 atlas->GetCustomRect(id, &r);
21671 const char* buf;
21672 ImFormatStringToTempBuffer(&buf, NULL, "ID:%08X, used:%d, { w:%3d, h:%3d } { x:%4d, y:%4d }", id, entry.IsUsed, r.w, r.h, r.x, r.y);
21674 Selectable(buf);
21675 if (IsItemHovered())
21676 highlight_r_id = id;
21678 Image(atlas->TexRef, ImVec2(r.w, r.h), r.uv0, r.uv1);
21679 }
21680 EndTable();
21681 }
21682 PopStyleVar();
21683 TreePop();
21684 }
21685
21686 // Texture list
21687 // (ensure the last texture always use the same ID, so we can keep it open neatly)
21688 ImFontAtlasRect highlight_r;
21689 if (highlight_r_id != ImFontAtlasRectId_Invalid)
21690 atlas->GetCustomRect(highlight_r_id, &highlight_r);
21691 for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++)
21692 {
21693 if (tex_n == atlas->TexList.Size - 1)
21695 DebugNodeTexture(atlas->TexList[tex_n], atlas->TexList.Size - 1 - tex_n, (highlight_r_id != ImFontAtlasRectId_Invalid) ? &highlight_r : NULL);
21696 }
21697}
21698
21699void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRect* highlight_rect)
21700{
21701 ImGuiContext& g = *GImGui;
21702 PushID(int_id);
21703 if (TreeNode("", "Texture #%03d (%dx%d pixels)", tex->UniqueID, tex->Width, tex->Height))
21704 {
21706 Checkbox("Show used rect", &cfg->ShowTextureUsedRect);
21709 if (tex->WantDestroyNextFrame)
21710 Dummy(ImVec2((float)tex->Width, (float)tex->Height));
21711 else
21712 ImageWithBg(tex->GetTexRef(), ImVec2((float)tex->Width, (float)tex->Height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
21713 if (cfg->ShowTextureUsedRect)
21714 GetWindowDrawList()->AddRect(ImVec2(p.x + tex->UsedRect.x, p.y + tex->UsedRect.y), ImVec2(p.x + tex->UsedRect.x + tex->UsedRect.w, p.y + tex->UsedRect.y + tex->UsedRect.h), IM_COL32(255, 0, 255, 255));
21715 if (highlight_rect != NULL)
21716 {
21717 ImRect r_outer(p.x, p.y, p.x + tex->Width, p.y + tex->Height);
21718 ImRect r_inner(p.x + highlight_rect->x, p.y + highlight_rect->y, p.x + highlight_rect->x + highlight_rect->w, p.y + highlight_rect->y + highlight_rect->h);
21719 RenderRectFilledWithHole(GetWindowDrawList(), r_outer, r_inner, IM_COL32(0, 0, 0, 100), 0.0f);
21720 GetWindowDrawList()->AddRect(r_inner.Min - ImVec2(1, 1), r_inner.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255));
21721 }
21722 PopStyleVar();
21723
21724 char texid_desc[30];
21725 Text("Status = %s (%d), Format = %s (%d), UseColors = %d", ImTextureDataGetStatusName(tex->Status), tex->Status, ImTextureDataGetFormatName(tex->Format), tex->Format, tex->UseColors);
21726 Text("TexID = %s, BackendUserData = %p", FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), tex->TexID), tex->BackendUserData);
21727 TreePop();
21728 }
21729 PopID();
21730}
21731
21733{
21734 ImGuiContext& g = *GImGui;
21735 ImGuiIO& io = g.IO;
21737 if (cfg->ShowDebugLog)
21739 if (cfg->ShowIDStackTool)
21741
21742 if (!Begin("Dear ImGui Metrics/Debugger", p_open) || GetCurrentWindow()->BeginCount > 1)
21743 {
21744 End();
21745 return;
21746 }
21747
21748 // [DEBUG] Clear debug breaks hooks after exactly one cycle.
21750
21751 // Basic info
21752 Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
21753 if (g.ContextName[0] != 0)
21754 {
21755 SameLine();
21756 Text("(Context Name: \"%s\")", g.ContextName);
21757 }
21758 Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
21759 Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
21760 Text("%d visible windows, %d current allocations", io.MetricsRenderWindows, g.DebugAllocInfo.TotalAllocCount - g.DebugAllocInfo.TotalFreeCount);
21761 //SameLine(); if (SmallButton("GC")) { g.GcCompactAll = true; }
21762
21763 Separator();
21764
21765 // Debugging enums
21766 enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentIdeal, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type
21767 const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentIdeal", "ContentRegionRect" };
21768 enum { TRT_OuterRect, TRT_InnerRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsWorkRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentFrozen, TRT_ColumnsContentUnfrozen, TRT_Count }; // Tables Rect Type
21769 const char* trt_rects_names[TRT_Count] = { "OuterRect", "InnerRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsWorkRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentFrozen", "ColumnsContentUnfrozen" };
21770 if (cfg->ShowWindowsRectsType < 0)
21771 cfg->ShowWindowsRectsType = WRT_WorkRect;
21772 if (cfg->ShowTablesRectsType < 0)
21773 cfg->ShowTablesRectsType = TRT_WorkRect;
21774
21775 struct Funcs
21776 {
21777 static ImRect GetTableRect(ImGuiTable* table, int rect_type, int n)
21778 {
21779 ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); // Always using last submitted instance
21780 if (rect_type == TRT_OuterRect) { return table->OuterRect; }
21781 else if (rect_type == TRT_InnerRect) { return table->InnerRect; }
21782 else if (rect_type == TRT_WorkRect) { return table->WorkRect; }
21783 else if (rect_type == TRT_HostClipRect) { return table->HostClipRect; }
21784 else if (rect_type == TRT_InnerClipRect) { return table->InnerClipRect; }
21785 else if (rect_type == TRT_BackgroundClipRect) { return table->BgClipRect; }
21786 else if (rect_type == TRT_ColumnsRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->MinX, table->InnerClipRect.Min.y, c->MaxX, table->InnerClipRect.Min.y + table_instance->LastOuterHeight); }
21787 else if (rect_type == TRT_ColumnsWorkRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->WorkRect.Min.y, c->WorkMaxX, table->WorkRect.Max.y); }
21788 else if (rect_type == TRT_ColumnsClipRect) { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; }
21789 else if (rect_type == TRT_ColumnsContentHeadersUsed){ ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table_instance->LastTopHeadersRowHeight); } // Note: y1/y2 not always accurate
21790 else if (rect_type == TRT_ColumnsContentHeadersIdeal){ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table_instance->LastTopHeadersRowHeight); }
21791 else if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight); }
21792 else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); }
21793 IM_ASSERT(0);
21794 return ImRect();
21795 }
21796
21797 static ImRect GetWindowRect(ImGuiWindow* window, int rect_type)
21798 {
21799 if (rect_type == WRT_OuterRect) { return window->Rect(); }
21800 else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; }
21801 else if (rect_type == WRT_InnerRect) { return window->InnerRect; }
21802 else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; }
21803 else if (rect_type == WRT_WorkRect) { return window->WorkRect; }
21804 else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
21805 else if (rect_type == WRT_ContentIdeal) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSizeIdeal); }
21806 else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; }
21807 IM_ASSERT(0);
21808 return ImRect();
21809 }
21810 };
21811
21812#ifdef IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
21813 TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS is enabled.\nMust disable after use! Otherwise Dear ImGui will run slower.\n");
21814#endif
21815
21816 // Tools
21817 if (TreeNode("Tools"))
21818 {
21819 // Debug Break features
21820 // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
21821 SeparatorTextEx(0, "Debug breaks", NULL, CalcTextSize("(?)").x + g.Style.SeparatorTextPadding.x);
21822 SameLine();
21823 MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash.");
21824 if (Checkbox("Show Item Picker", &g.DebugItemPickerActive) && g.DebugItemPickerActive)
21826 Checkbox("Show \"Debug Break\" buttons in other sections (io.ConfigDebugIsDebuggerPresent)", &g.IO.ConfigDebugIsDebuggerPresent);
21827
21828 SeparatorText("Visualize");
21829
21830 Checkbox("Show Debug Log", &cfg->ShowDebugLog);
21831 SameLine();
21832 MetricsHelpMarker("You can also call ImGui::ShowDebugLogWindow() from your code.");
21833
21834 Checkbox("Show ID Stack Tool", &cfg->ShowIDStackTool);
21835 SameLine();
21836 MetricsHelpMarker("You can also call ImGui::ShowIDStackToolWindow() from your code.");
21837
21838 Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder);
21839 Checkbox("Show windows rectangles", &cfg->ShowWindowsRects);
21840 SameLine();
21842 cfg->ShowWindowsRects |= Combo("##show_windows_rect_type", &cfg->ShowWindowsRectsType, wrt_rects_names, WRT_Count, WRT_Count);
21843 if (cfg->ShowWindowsRects && g.NavWindow != NULL)
21844 {
21845 BulletText("'%s':", g.NavWindow->Name);
21846 Indent();
21847 for (int rect_n = 0; rect_n < WRT_Count; rect_n++)
21848 {
21849 ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n);
21850 Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]);
21851 }
21852 Unindent();
21853 }
21854
21855 Checkbox("Show tables rectangles", &cfg->ShowTablesRects);
21856 SameLine();
21858 cfg->ShowTablesRects |= Combo("##show_table_rects_type", &cfg->ShowTablesRectsType, trt_rects_names, TRT_Count, TRT_Count);
21859 if (cfg->ShowTablesRects && g.NavWindow != NULL)
21860 {
21861 for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++)
21862 {
21863 ImGuiTable* table = g.Tables.TryGetMapData(table_n);
21864 if (table == NULL || table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow))
21865 continue;
21866
21867 BulletText("Table 0x%08X (%d columns, in '%s')", table->ID, table->ColumnsCount, table->OuterWindow->Name);
21868 if (IsItemHovered())
21869 GetForegroundDrawList()->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
21870 Indent();
21871 char buf[128];
21872 for (int rect_n = 0; rect_n < TRT_Count; rect_n++)
21873 {
21874 if (rect_n >= TRT_ColumnsRect)
21875 {
21876 if (rect_n != TRT_ColumnsRect && rect_n != TRT_ColumnsClipRect)
21877 continue;
21878 for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
21879 {
21880 ImRect r = Funcs::GetTableRect(table, rect_n, column_n);
21881 ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) Col %d %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), column_n, trt_rects_names[rect_n]);
21882 Selectable(buf);
21883 if (IsItemHovered())
21884 GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
21885 }
21886 }
21887 else
21888 {
21889 ImRect r = Funcs::GetTableRect(table, rect_n, -1);
21890 ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), trt_rects_names[rect_n]);
21891 Selectable(buf);
21892 if (IsItemHovered())
21893 GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
21894 }
21895 }
21896 Unindent();
21897 }
21898 }
21899 Checkbox("Show groups rectangles", &g.DebugShowGroupRects); // Storing in context as this is used by group code and prefers to be in hot-data
21900
21901 SeparatorText("Validate");
21902
21903 Checkbox("Debug Begin/BeginChild return value", &io.ConfigDebugBeginReturnValueLoop);
21904 SameLine();
21905 MetricsHelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.");
21906
21907 Checkbox("UTF-8 Encoding viewer", &cfg->ShowTextEncodingViewer);
21908 SameLine();
21909 MetricsHelpMarker("You can also call ImGui::DebugTextEncoding() from your code with a given string to test that your UTF-8 encoding settings are correct.");
21910 if (cfg->ShowTextEncodingViewer)
21911 {
21912 static char buf[64] = "";
21913 SetNextItemWidth(-FLT_MIN);
21914 InputText("##DebugTextEncodingBuf", buf, IM_ARRAYSIZE(buf));
21915 if (buf[0] != 0)
21916 DebugTextEncoding(buf);
21917 }
21918
21919 TreePop();
21920 }
21921
21922 // Windows
21923 if (TreeNode("Windows", "Windows (%d)", g.Windows.Size))
21924 {
21925 //SetNextItemOpen(true, ImGuiCond_Once);
21926 DebugNodeWindowsList(&g.Windows, "By display order");
21927 DebugNodeWindowsList(&g.WindowsFocusOrder, "By focus order (root windows)");
21928 if (TreeNode("By submission order (begin stack)"))
21929 {
21930 // Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship!
21932 temp_buffer.resize(0);
21933 for (ImGuiWindow* window : g.Windows)
21934 if (window->LastFrameActive + 1 >= g.FrameCount)
21935 temp_buffer.push_back(window);
21936 struct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const *)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } };
21937 ImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder);
21938 DebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL);
21939 TreePop();
21940 }
21941
21942 TreePop();
21943 }
21944
21945 // DrawLists
21946 int drawlist_count = 0;
21947 for (ImGuiViewportP* viewport : g.Viewports)
21948 drawlist_count += viewport->DrawDataP.CmdLists.Size;
21949 if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count))
21950 {
21951 Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh);
21952 Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes);
21953 for (ImGuiViewportP* viewport : g.Viewports)
21954 {
21955 bool viewport_has_drawlist = false;
21956 for (ImDrawList* draw_list : viewport->DrawDataP.CmdLists)
21957 {
21958 if (!viewport_has_drawlist)
21959 Text("Active DrawLists in Viewport #%d, ID: 0x%08X", viewport->Idx, viewport->ID);
21960 viewport_has_drawlist = true;
21961 DebugNodeDrawList(NULL, viewport, draw_list, "DrawList");
21962 }
21963 }
21964 TreePop();
21965 }
21966
21967 // Viewports
21968 if (TreeNode("Viewports", "Viewports (%d)", g.Viewports.Size))
21969 {
21970 cfg->HighlightMonitorIdx = -1;
21971 bool open = TreeNode("Monitors", "Monitors (%d)", g.PlatformIO.Monitors.Size);
21972 SameLine();
21973 MetricsHelpMarker("Dear ImGui uses monitor data:\n- to query DPI settings on a per monitor basis\n- to position popup/tooltips so they don't straddle monitors.");
21974 if (open)
21975 {
21976 for (int i = 0; i < g.PlatformIO.Monitors.Size; i++)
21977 {
21978 DebugNodePlatformMonitor(&g.PlatformIO.Monitors[i], "Monitor", i);
21979 if (IsItemHovered())
21980 cfg->HighlightMonitorIdx = i;
21981 }
21982 DebugNodePlatformMonitor(&g.FallbackMonitor, "Fallback", 0);
21983 TreePop();
21984 }
21985
21987 if (TreeNode("Windows Minimap"))
21988 {
21990 TreePop();
21991 }
21992 cfg->HighlightViewportID = 0;
21993
21994 BulletText("MouseViewport: 0x%08X (UserHovered 0x%08X, LastHovered 0x%08X)", g.MouseViewport ? g.MouseViewport->ID : 0, g.IO.MouseHoveredViewport, g.MouseLastHoveredViewport ? g.MouseLastHoveredViewport->ID : 0);
21995 if (TreeNode("Inferred Z order (front-to-back)"))
21996 {
21997 static ImVector<ImGuiViewportP*> viewports;
21998 viewports.resize(g.Viewports.Size);
21999 memcpy(viewports.Data, g.Viewports.Data, g.Viewports.size_in_bytes());
22000 if (viewports.Size > 1)
22002 for (ImGuiViewportP* viewport : viewports)
22003 {
22004 BulletText("Viewport #%d, ID: 0x%08X, LastFocused = %08d, PlatformFocused = %s, Window: \"%s\"",
22005 viewport->Idx, viewport->ID, viewport->LastFocusedStampCount,
22006 (g.PlatformIO.Platform_GetWindowFocus && viewport->PlatformWindowCreated) ? (g.PlatformIO.Platform_GetWindowFocus(viewport) ? "1" : "0") : "N/A",
22007 viewport->Window ? viewport->Window->Name : "N/A");
22008 if (IsItemHovered())
22009 cfg->HighlightViewportID = viewport->ID;
22010 }
22011 TreePop();
22012 }
22013
22014 for (ImGuiViewportP* viewport : g.Viewports)
22015 DebugNodeViewport(viewport);
22016 TreePop();
22017 }
22018
22019 // Details for Fonts
22020 for (ImFontAtlas* atlas : g.FontAtlases)
22021 if (TreeNode((void*)atlas, "Fonts (%d), Textures (%d)", atlas->Fonts.Size, atlas->TexList.Size))
22022 {
22023 ShowFontAtlas(atlas);
22024 TreePop();
22025 }
22026
22027 // Details for Popups
22028 if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size))
22029 {
22030 for (const ImGuiPopupData& popup_data : g.OpenPopupStack)
22031 {
22032 // As it's difficult to interact with tree nodes while popups are open, we display everything inline.
22033 ImGuiWindow* window = popup_data.Window;
22034 BulletText("PopupID: %08x, Window: '%s' (%s%s), RestoreNavWindow '%s', ParentWindow '%s'",
22035 popup_data.PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? "Child;" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? "Menu;" : "",
22036 popup_data.RestoreNavWindow ? popup_data.RestoreNavWindow->Name : "NULL", window && window->ParentWindow ? window->ParentWindow->Name : "NULL");
22037 }
22038 TreePop();
22039 }
22040
22041 // Details for TabBars
22042 if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetAliveCount()))
22043 {
22044 for (int n = 0; n < g.TabBars.GetMapSize(); n++)
22045 if (ImGuiTabBar* tab_bar = g.TabBars.TryGetMapData(n))
22046 {
22047 PushID(tab_bar);
22048 DebugNodeTabBar(tab_bar, "TabBar");
22049 PopID();
22050 }
22051 TreePop();
22052 }
22053
22054 // Details for Tables
22055 if (TreeNode("Tables", "Tables (%d)", g.Tables.GetAliveCount()))
22056 {
22057 for (int n = 0; n < g.Tables.GetMapSize(); n++)
22058 if (ImGuiTable* table = g.Tables.TryGetMapData(n))
22059 DebugNodeTable(table);
22060 TreePop();
22061 }
22062
22063 // Details for InputText
22064 if (TreeNode("InputText"))
22065 {
22067 TreePop();
22068 }
22069
22070 // Details for TypingSelect
22071 if (TreeNode("TypingSelect", "TypingSelect (%d)", g.TypingSelectState.SearchBuffer[0] != 0 ? 1 : 0))
22072 {
22074 TreePop();
22075 }
22076
22077 // Details for MultiSelect
22078 if (TreeNode("MultiSelect", "MultiSelect (%d)", g.MultiSelectStorage.GetAliveCount()))
22079 {
22081 BulletText("BoxSelect ID=0x%08X, Starting = %d, Active %d", bs->ID, bs->IsStarting, bs->IsActive);
22082 for (int n = 0; n < g.MultiSelectStorage.GetMapSize(); n++)
22085 TreePop();
22086 }
22087
22088 // Details for Docking
22089#ifdef IMGUI_HAS_DOCK
22090 if (TreeNode("Docking"))
22091 {
22092 static bool root_nodes_only = true;
22094 Checkbox("List root nodes", &root_nodes_only);
22095 Checkbox("Ctrl shows window dock info", &cfg->ShowDockingNodes);
22096 if (SmallButton("Clear nodes")) { DockContextClearNodes(&g, 0, true); }
22097 SameLine();
22098 if (SmallButton("Rebuild all")) { dc->WantFullRebuild = true; }
22099 for (int n = 0; n < dc->Nodes.Data.Size; n++)
22100 if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
22101 if (!root_nodes_only || node->IsRootNode())
22102 DebugNodeDockNode(node, "Node");
22103 TreePop();
22104 }
22105#endif // #ifdef IMGUI_HAS_DOCK
22106
22107 // Settings
22108 if (TreeNode("Settings"))
22109 {
22110 if (SmallButton("Clear"))
22112 SameLine();
22113 if (SmallButton("Save to memory"))
22115 SameLine();
22116 if (SmallButton("Save to disk"))
22118 SameLine();
22119 if (g.IO.IniFilename)
22120 Text("\"%s\"", g.IO.IniFilename);
22121 else
22122 TextUnformatted("<NULL>");
22123 Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings);
22124 Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer);
22125 if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size))
22126 {
22127 for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
22128 BulletText("\"%s\"", handler.TypeName);
22129 TreePop();
22130 }
22131 if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size()))
22132 {
22133 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
22134 DebugNodeWindowSettings(settings);
22135 TreePop();
22136 }
22137
22138 if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size()))
22139 {
22140 for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
22141 DebugNodeTableSettings(settings);
22142 TreePop();
22143 }
22144
22145#ifdef IMGUI_HAS_DOCK
22146 if (TreeNode("SettingsDocking", "Settings packed data: Docking"))
22147 {
22149 Text("In SettingsWindows:");
22150 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
22151 if (settings->DockId != 0)
22152 BulletText("Window '%s' -> DockId %08X DockOrder=%d", settings->GetName(), settings->DockId, settings->DockOrder);
22153 Text("In SettingsNodes:");
22154 for (int n = 0; n < dc->NodesSettings.Size; n++)
22155 {
22156 ImGuiDockNodeSettings* settings = &dc->NodesSettings[n];
22157 const char* selected_tab_name = NULL;
22158 if (settings->SelectedTabId)
22159 {
22160 if (ImGuiWindow* window = FindWindowByID(settings->SelectedTabId))
22161 selected_tab_name = window->Name;
22162 else if (ImGuiWindowSettings* window_settings = FindWindowSettingsByID(settings->SelectedTabId))
22163 selected_tab_name = window_settings->GetName();
22164 }
22165 BulletText("Node %08X, Parent %08X, SelectedTab %08X ('%s')", settings->ID, settings->ParentNodeId, settings->SelectedTabId, selected_tab_name ? selected_tab_name : settings->SelectedTabId ? "N/A" : "");
22166 }
22167 TreePop();
22168 }
22169#endif // #ifdef IMGUI_HAS_DOCK
22170
22171 if (TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size()))
22172 {
22174 TreePop();
22175 }
22176 TreePop();
22177 }
22178
22179 // Settings
22180 if (TreeNode("Memory allocations"))
22181 {
22183 Text("%d current allocations", info->TotalAllocCount - info->TotalFreeCount);
22184 if (SmallButton("GC now")) { g.GcCompactAll = true; }
22185 Text("Recent frames with allocations:");
22186 int buf_size = IM_ARRAYSIZE(info->LastEntriesBuf);
22187 for (int n = buf_size - 1; n >= 0; n--)
22188 {
22189 ImGuiDebugAllocEntry* entry = &info->LastEntriesBuf[(info->LastEntriesIdx - n + buf_size) % buf_size];
22190 BulletText("Frame %06d: %+3d ( %2d alloc, %2d free )", entry->FrameCount, entry->AllocCount - entry->FreeCount, entry->AllocCount, entry->FreeCount);
22191 if (n == 0)
22192 {
22193 SameLine();
22194 Text("<- %d frames ago", g.FrameCount - entry->FrameCount);
22195 }
22196 }
22197 TreePop();
22198 }
22199
22200 if (TreeNode("Inputs"))
22201 {
22202 Text("KEYBOARD/GAMEPAD/MOUSE KEYS");
22203 {
22204 // User code should never have to go through such hoops! You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END.
22205 Indent();
22206 Text("Keys down:"); for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (!IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); }
22207 Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (!IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); }
22208 Text("Keys released:"); for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (!IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); }
22209 Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
22210 Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; SameLine(); Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
22212 Unindent();
22213 }
22214
22215 Text("MOUSE STATE");
22216 {
22217 Indent();
22218 if (IsMousePosValid())
22219 Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
22220 else
22221 Text("Mouse pos: <INVALID>");
22222 Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
22223 int count = IM_ARRAYSIZE(io.MouseDown);
22224 Text("Mouse down:"); for (int i = 0; i < count; i++) if (IsMouseDown(i)) { SameLine(); Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
22225 Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (IsMouseClicked(i)) { SameLine(); Text("b%d (%d)", i, io.MouseClickedCount[i]); }
22226 Text("Mouse released:"); for (int i = 0; i < count; i++) if (IsMouseReleased(i)) { SameLine(); Text("b%d", i); }
22227 Text("Mouse wheel: %.1f", io.MouseWheel);
22228 Text("MouseStationaryTimer: %.2f", g.MouseStationaryTimer);
22229 Text("Mouse source: %s", GetMouseSourceName(io.MouseSource));
22230 Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused
22231 Unindent();
22232 }
22233
22234 Text("MOUSE WHEELING");
22235 {
22236 Indent();
22237 Text("WheelingWindow: '%s'", g.WheelingWindow ? g.WheelingWindow->Name : "NULL");
22238 Text("WheelingWindowReleaseTimer: %.2f", g.WheelingWindowReleaseTimer);
22239 Text("WheelingAxisAvg[] = { %.3f, %.3f }, Main Axis: %s", g.WheelingAxisAvg.x, g.WheelingAxisAvg.y, (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? "X" : (g.WheelingAxisAvg.x < g.WheelingAxisAvg.y) ? "Y" : "<none>");
22240 Unindent();
22241 }
22242
22243 Text("KEY OWNERS");
22244 {
22245 Indent();
22247 for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
22248 {
22249 ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
22250 if (owner_data->OwnerCurr == ImGuiKeyOwner_NoOwner)
22251 continue;
22252 Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr,
22253 owner_data->LockUntilRelease ? " LockUntilRelease" : owner_data->LockThisFrame ? " LockThisFrame" : "");
22254 DebugLocateItemOnHover(owner_data->OwnerCurr);
22255 }
22256 EndChild();
22257 Unindent();
22258 }
22259 Text("SHORTCUT ROUTING");
22260 SameLine();
22261 MetricsHelpMarker("Declared shortcut routes automatically set key owner when mods matches.");
22262 {
22263 Indent();
22265 for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
22266 {
22268 for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; )
22269 {
22270 ImGuiKeyRoutingData* routing_data = &rt->Entries[idx];
22271 ImGuiKeyChord key_chord = key | routing_data->Mods;
22272 Text("%s: 0x%08X (scored %d)", GetKeyChordName(key_chord), routing_data->RoutingCurr, routing_data->RoutingCurrScore);
22273 DebugLocateItemOnHover(routing_data->RoutingCurr);
22275 {
22276 SameLine();
22277 if (DebugBreakButton("**DebugBreak**", "in SetShortcutRouting() for this KeyChord"))
22278 g.DebugBreakInShortcutRouting = key_chord;
22279 }
22280 idx = routing_data->NextEntryIndex;
22281 }
22282 }
22283 EndChild();
22284 Text("(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask);
22285 Unindent();
22286 }
22287 TreePop();
22288 }
22289
22290 if (TreeNode("Internal state"))
22291 {
22292 Text("WINDOWING");
22293 Indent();
22294 Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
22295 Text("HoveredWindow->Root: '%s'", g.HoveredWindow ? g.HoveredWindow->RootWindowDockTree->Name : "NULL");
22296 Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL");
22297 Text("HoveredDockNode: 0x%08X", g.DebugHoveredDockNode ? g.DebugHoveredDockNode->ID : 0);
22298 Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL");
22299 Text("MouseViewport: 0x%08X (UserHovered 0x%08X, LastHovered 0x%08X)", g.MouseViewport->ID, g.IO.MouseHoveredViewport, g.MouseLastHoveredViewport ? g.MouseLastHoveredViewport->ID : 0);
22300 Unindent();
22301
22302 Text("ITEMS");
22303 Indent();
22304 Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, GetInputSourceName(g.ActiveIdSource));
22306 Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
22307 Text("ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: %X", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask);
22308 Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame
22309 Text("HoverItemDelayId: 0x%08X, Timer: %.2f, ClearTimer: %.2f", g.HoverItemDelayId, g.HoverItemDelayTimer, g.HoverItemDelayClearTimer);
22310 Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
22312 Unindent();
22313
22314 Text("NAV,FOCUS");
22315 Indent();
22316 Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
22317 Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
22319 Text("NavInputSource: %s", GetInputSourceName(g.NavInputSource));
22320 Text("NavLastValidSelectionUserData = %" IM_PRId64 " (0x%" IM_PRIX64 ")", g.NavLastValidSelectionUserData, g.NavLastValidSelectionUserData);
22321 Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
22322 Text("NavActivateId/DownId/PressedId: %08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId);
22323 Text("NavActivateFlags: %04X", g.NavActivateFlags);
22324 Text("NavCursorVisible: %d, NavHighlightItemUnderNav: %d", g.NavCursorVisible, g.NavHighlightItemUnderNav);
22325 Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId);
22326 Text("NavFocusRoute[] = ");
22327 for (int path_n = g.NavFocusRoute.Size - 1; path_n >= 0; path_n--)
22328 {
22329 const ImGuiFocusScopeData& focus_scope = g.NavFocusRoute[path_n];
22330 SameLine(0.0f, 0.0f);
22331 Text("0x%08X/", focus_scope.ID);
22332 SetItemTooltip("In window \"%s\"", FindWindowByID(focus_scope.WindowID)->Name);
22333 }
22334 Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL");
22335 Unindent();
22336
22337 TreePop();
22338 }
22339
22340 // Overlay: Display windows Rectangles and Begin Order
22341 if (cfg->ShowWindowsRects || cfg->ShowWindowsBeginOrder)
22342 {
22343 for (ImGuiWindow* window : g.Windows)
22344 {
22345 if (!window->WasActive)
22346 continue;
22347 ImDrawList* draw_list = GetForegroundDrawList(window);
22348 if (cfg->ShowWindowsRects)
22349 {
22350 ImRect r = Funcs::GetWindowRect(window, cfg->ShowWindowsRectsType);
22351 draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
22352 }
22354 {
22355 char buf[32];
22356 ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext);
22357 float font_size = GetFontSize();
22358 draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255));
22359 draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf);
22360 }
22361 }
22362 }
22363
22364 // Overlay: Display Tables Rectangles
22365 if (cfg->ShowTablesRects)
22366 {
22367 for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++)
22368 {
22369 ImGuiTable* table = g.Tables.TryGetMapData(table_n);
22370 if (table == NULL || table->LastFrameActive < g.FrameCount - 1)
22371 continue;
22372 ImDrawList* draw_list = GetForegroundDrawList(table->OuterWindow);
22373 if (cfg->ShowTablesRectsType >= TRT_ColumnsRect)
22374 {
22375 for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
22376 {
22377 ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, column_n);
22378 ImU32 col = (table->HoveredColumnBody == column_n) ? IM_COL32(255, 255, 128, 255) : IM_COL32(255, 0, 128, 255);
22379 float thickness = (table->HoveredColumnBody == column_n) ? 3.0f : 1.0f;
22380 draw_list->AddRect(r.Min, r.Max, col, 0.0f, 0, thickness);
22381 }
22382 }
22383 else
22384 {
22385 ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, -1);
22386 draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
22387 }
22388 }
22389 }
22390
22391#ifdef IMGUI_HAS_DOCK
22392 // Overlay: Display Docking info
22394 {
22395 char buf[64] = "";
22396 char* p = buf;
22399 p += ImFormatString(p, buf + IM_ARRAYSIZE(buf) - p, "DockId: %X%s\n", node->ID, node->IsCentralNode() ? " *CentralNode*" : "");
22400 p += ImFormatString(p, buf + IM_ARRAYSIZE(buf) - p, "WindowClass: %08X\n", node->WindowClass.ClassId);
22401 p += ImFormatString(p, buf + IM_ARRAYSIZE(buf) - p, "Size: (%.0f, %.0f)\n", node->Size.x, node->Size.y);
22402 p += ImFormatString(p, buf + IM_ARRAYSIZE(buf) - p, "SizeRef: (%.0f, %.0f)\n", node->SizeRef.x, node->SizeRef.y);
22403 int depth = DockNodeGetDepth(node);
22404 overlay_draw_list->AddRect(node->Pos + ImVec2(3, 3) * (float)depth, node->Pos + node->Size - ImVec2(3, 3) * (float)depth, IM_COL32(200, 100, 100, 255));
22405 ImVec2 pos = node->Pos + ImVec2(3, 3) * (float)depth;
22406 overlay_draw_list->AddRectFilled(pos - ImVec2(1, 1), pos + CalcTextSize(buf) + ImVec2(1, 1), IM_COL32(200, 100, 100, 255));
22407 overlay_draw_list->AddText(NULL, 0.0f, pos, IM_COL32(255, 255, 255, 255), buf);
22408 }
22409#endif // #ifdef IMGUI_HAS_DOCK
22410
22411 End();
22412}
22413
22415{
22416 // Those fields are scattered in their respective subsystem to stay in hot-data locations
22417 ImGuiContext& g = *GImGui;
22418 g.DebugBreakInWindow = 0;
22419 g.DebugBreakInTable = 0;
22421}
22422
22423void ImGui::DebugBreakButtonTooltip(bool keyboard_only, const char* description_of_location)
22424{
22425 if (!BeginItemTooltip())
22426 return;
22427 Text("To call IM_DEBUG_BREAK() %s:", description_of_location);
22428 Separator();
22429 TextUnformatted(keyboard_only ? "- Press 'Pause/Break' on keyboard." : "- Press 'Pause/Break' on keyboard.\n- or Click (may alter focus/active id).\n- or navigate using keyboard and press space.");
22430 Separator();
22431 TextUnformatted("Choose one way that doesn't interfere with what you are trying to debug!\nYou need a debugger attached or this will crash!");
22432 EndTooltip();
22433}
22434
22435// Special button that doesn't take focus, doesn't take input owner, and can be activated without a click etc.
22436// In order to reduce interferences with the contents we are trying to debug into.
22437bool ImGui::DebugBreakButton(const char* label, const char* description_of_location)
22438{
22439 ImGuiWindow* window = GetCurrentWindow();
22440 if (window->SkipItems)
22441 return false;
22442
22443 ImGuiContext& g = *GImGui;
22444 const ImGuiID id = window->GetID(label);
22445 const ImVec2 label_size = CalcTextSize(label, NULL, true);
22446 ImVec2 pos = window->DC.CursorPos + ImVec2(0.0f, window->DC.CurrLineTextBaseOffset);
22447 ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x * 2.0f, label_size.y);
22448
22449 const ImRect bb(pos, pos + size);
22450 ItemSize(size, 0.0f);
22451 if (!ItemAdd(bb, id))
22452 return false;
22453
22454 // WE DO NOT USE ButtonEx() or ButtonBehavior() in order to reduce our side-effects.
22455 bool hovered = ItemHoverable(bb, id, g.CurrentItemFlags);
22456 bool pressed = hovered && (IsKeyChordPressed(g.DebugBreakKeyChord) || IsMouseClicked(0) || g.NavActivateId == id);
22457 DebugBreakButtonTooltip(false, description_of_location);
22458
22460 ImVec4 hsv;
22461 ColorConvertRGBtoHSV(col4f.x, col4f.y, col4f.z, hsv.x, hsv.y, hsv.z);
22462 ColorConvertHSVtoRGB(hsv.x + 0.20f, hsv.y, hsv.z, col4f.x, col4f.y, col4f.z);
22463
22464 RenderNavCursor(bb, id);
22465 RenderFrame(bb.Min, bb.Max, GetColorU32(col4f), true, g.Style.FrameRounding);
22466 RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, g.Style.ButtonTextAlign, &bb);
22467
22469 return pressed;
22470}
22471
22472// [DEBUG] Display contents of Columns
22474{
22475 if (!TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
22476 return;
22477 BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
22478 for (ImGuiOldColumnData& column : columns->Columns)
22479 BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", (int)columns->Columns.index_from_ptr(&column), column.OffsetNorm, GetColumnOffsetFromNorm(columns, column.OffsetNorm));
22480 TreePop();
22481}
22482
22483static void DebugNodeDockNodeFlags(ImGuiDockNodeFlags* p_flags, const char* label, bool enabled)
22484{
22485 using namespace ImGui;
22486 PushID(label);
22487 PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
22488 Text("%s:", label);
22489 if (!enabled)
22490 BeginDisabled();
22491 CheckboxFlags("NoResize", p_flags, ImGuiDockNodeFlags_NoResize);
22492 CheckboxFlags("NoResizeX", p_flags, ImGuiDockNodeFlags_NoResizeX);
22493 CheckboxFlags("NoResizeY",p_flags, ImGuiDockNodeFlags_NoResizeY);
22494 CheckboxFlags("NoTabBar", p_flags, ImGuiDockNodeFlags_NoTabBar);
22495 CheckboxFlags("HiddenTabBar", p_flags, ImGuiDockNodeFlags_HiddenTabBar);
22496 CheckboxFlags("NoWindowMenuButton", p_flags, ImGuiDockNodeFlags_NoWindowMenuButton);
22497 CheckboxFlags("NoCloseButton", p_flags, ImGuiDockNodeFlags_NoCloseButton);
22498 CheckboxFlags("DockedWindowsInFocusRoute", p_flags, ImGuiDockNodeFlags_DockedWindowsInFocusRoute);
22499 CheckboxFlags("NoDocking", p_flags, ImGuiDockNodeFlags_NoDocking); // Multiple flags
22500 CheckboxFlags("NoDockingSplit", p_flags, ImGuiDockNodeFlags_NoDockingSplit);
22501 CheckboxFlags("NoDockingSplitOther", p_flags, ImGuiDockNodeFlags_NoDockingSplitOther);
22502 CheckboxFlags("NoDockingOver", p_flags, ImGuiDockNodeFlags_NoDockingOverMe);
22503 CheckboxFlags("NoDockingOverOther", p_flags, ImGuiDockNodeFlags_NoDockingOverOther);
22504 CheckboxFlags("NoDockingOverEmpty", p_flags, ImGuiDockNodeFlags_NoDockingOverEmpty);
22505 CheckboxFlags("NoUndocking", p_flags, ImGuiDockNodeFlags_NoUndocking);
22506 if (!enabled)
22507 EndDisabled();
22508 PopStyleVar();
22509 PopID();
22510}
22511
22512// [DEBUG] Display contents of ImDockNode
22513void ImGui::DebugNodeDockNode(ImGuiDockNode* node, const char* label)
22514{
22515 ImGuiContext& g = *GImGui;
22516 const bool is_alive = (g.FrameCount - node->LastFrameAlive < 2); // Submitted with ImGuiDockNodeFlags_KeepAliveOnly
22517 const bool is_active = (g.FrameCount - node->LastFrameActive < 2); // Submitted
22519 bool open;
22521 if (node->Windows.Size > 0)
22522 open = TreeNodeEx((void*)(intptr_t)node->ID, tree_node_flags, "%s 0x%04X%s: %d windows (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", node->Windows.Size, node->VisibleWindow ? node->VisibleWindow->Name : "NULL");
22523 else
22524 open = TreeNodeEx((void*)(intptr_t)node->ID, tree_node_flags, "%s 0x%04X%s: %s (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", (node->SplitAxis == ImGuiAxis_X) ? "horizontal split" : (node->SplitAxis == ImGuiAxis_Y) ? "vertical split" : "empty", node->VisibleWindow ? node->VisibleWindow->Name : "NULL");
22525 if (!is_alive) { PopStyleColor(); }
22526 if (is_active && IsItemHovered())
22527 if (ImGuiWindow* window = node->HostWindow ? node->HostWindow : node->VisibleWindow)
22528 GetForegroundDrawList(window)->AddRect(node->Pos, node->Pos + node->Size, IM_COL32(255, 255, 0, 255));
22529 if (open)
22530 {
22531 IM_ASSERT(node->ChildNodes[0] == NULL || node->ChildNodes[0]->ParentNode == node);
22532 IM_ASSERT(node->ChildNodes[1] == NULL || node->ChildNodes[1]->ParentNode == node);
22533 BulletText("Pos (%.0f,%.0f), Size (%.0f, %.0f) Ref (%.0f, %.0f)",
22534 node->Pos.x, node->Pos.y, node->Size.x, node->Size.y, node->SizeRef.x, node->SizeRef.y);
22535 DebugNodeWindow(node->HostWindow, "HostWindow");
22536 DebugNodeWindow(node->VisibleWindow, "VisibleWindow");
22537 BulletText("SelectedTabID: 0x%08X, LastFocusedNodeID: 0x%08X", node->SelectedTabId, node->LastFocusedNodeId);
22538 BulletText("Misc:%s%s%s%s%s%s%s",
22539 node->IsDockSpace() ? " IsDockSpace" : "",
22540 node->IsCentralNode() ? " IsCentralNode" : "",
22541 is_alive ? " IsAlive" : "", is_active ? " IsActive" : "", node->IsFocused ? " IsFocused" : "",
22542 node->WantLockSizeOnce ? " WantLockSizeOnce" : "",
22543 node->HasCentralNodeChild ? " HasCentralNodeChild" : "");
22544 if (TreeNode("flags", "Flags Merged: 0x%04X, Local: 0x%04X, InWindows: 0x%04X, Shared: 0x%04X", node->MergedFlags, node->LocalFlags, node->LocalFlagsInWindows, node->SharedFlags))
22545 {
22546 if (BeginTable("flags", 4))
22547 {
22548 TableNextColumn(); DebugNodeDockNodeFlags(&node->MergedFlags, "MergedFlags", false);
22549 TableNextColumn(); DebugNodeDockNodeFlags(&node->LocalFlags, "LocalFlags", true);
22550 TableNextColumn(); DebugNodeDockNodeFlags(&node->LocalFlagsInWindows, "LocalFlagsInWindows", false);
22551 TableNextColumn(); DebugNodeDockNodeFlags(&node->SharedFlags, "SharedFlags", true);
22552 EndTable();
22553 }
22554 TreePop();
22555 }
22556 if (node->ParentNode)
22557 DebugNodeDockNode(node->ParentNode, "ParentNode");
22558 if (node->ChildNodes[0])
22559 DebugNodeDockNode(node->ChildNodes[0], "Child[0]");
22560 if (node->ChildNodes[1])
22561 DebugNodeDockNode(node->ChildNodes[1], "Child[1]");
22562 if (node->TabBar)
22563 DebugNodeTabBar(node->TabBar, "TabBar");
22564 DebugNodeWindowsList(&node->Windows, "Windows");
22565
22566 TreePop();
22567 }
22568}
22569
22570// [DEBUG] Display contents of ImDrawList
22571// Note that both 'window' and 'viewport' may be NULL here. Viewport is generally null of destroyed popups which previously owned a viewport.
22572void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label)
22573{
22574 ImGuiContext& g = *GImGui;
22576 int cmd_count = draw_list->CmdBuffer.Size;
22577 if (cmd_count > 0 && draw_list->CmdBuffer.back().ElemCount == 0 && draw_list->CmdBuffer.back().UserCallback == NULL)
22578 cmd_count--;
22579 bool node_open = TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, cmd_count);
22580 if (draw_list == GetWindowDrawList())
22581 {
22582 SameLine();
22583 TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered)
22584 if (node_open)
22585 TreePop();
22586 return;
22587 }
22588
22589 ImDrawList* fg_draw_list = viewport ? GetForegroundDrawList(viewport) : NULL; // Render additional visuals into the top-most draw list
22590 if (window && IsItemHovered() && fg_draw_list)
22591 fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
22592 if (!node_open)
22593 return;
22594
22595 if (window && !window->WasActive)
22596 TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!");
22597
22598 for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.Data; pcmd < draw_list->CmdBuffer.Data + cmd_count; pcmd++)
22599 {
22600 if (pcmd->UserCallback)
22601 {
22602 BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
22603 continue;
22604 }
22605
22606 char texid_desc[30];
22607 FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), pcmd);
22608 char buf[300];
22609 ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex %s, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
22610 pcmd->ElemCount / 3, texid_desc, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
22611 bool pcmd_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf);
22612 if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list)
22613 DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes);
22614 if (!pcmd_node_open)
22615 continue;
22616
22617 // Calculate approximate coverage area (touched pixel count)
22618 // This will be in pixels squared as long there's no post-scaling happening to the renderer output.
22619 const ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
22620 const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + pcmd->VtxOffset;
22621 float total_area = 0.0f;
22622 for (unsigned int idx_n = pcmd->IdxOffset; idx_n < pcmd->IdxOffset + pcmd->ElemCount; )
22623 {
22624 ImVec2 triangle[3];
22625 for (int n = 0; n < 3; n++, idx_n++)
22626 triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos;
22627 total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]);
22628 }
22629
22630 // Display vertex information summary. Hover to get all triangles drawn in wire-frame
22631 ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area);
22632 Selectable(buf);
22633 if (IsItemHovered() && fg_draw_list)
22634 DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, true, false);
22635
22636 // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
22637 ImGuiListClipper clipper;
22638 clipper.Begin(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
22639 while (clipper.Step())
22640 for (int prim = clipper.DisplayStart, idx_i = pcmd->IdxOffset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++)
22641 {
22642 char* buf_p = buf, * buf_end = buf + IM_ARRAYSIZE(buf);
22643 ImVec2 triangle[3];
22644 for (int n = 0; n < 3; n++, idx_i++)
22645 {
22646 const ImDrawVert& v = vtx_buffer[idx_buffer ? idx_buffer[idx_i] : idx_i];
22647 triangle[n] = v.pos;
22648 buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n",
22649 (n == 0) ? "Vert:" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
22650 }
22651
22652 Selectable(buf, false);
22653 if (fg_draw_list && IsItemHovered())
22654 {
22655 ImDrawListFlags backup_flags = fg_draw_list->Flags;
22656 fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
22657 fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f);
22658 fg_draw_list->Flags = backup_flags;
22659 }
22660 }
22661 TreePop();
22662 }
22663 TreePop();
22664}
22665
22666// [DEBUG] Display mesh/aabb of a ImDrawCmd
22667void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb)
22668{
22669 IM_ASSERT(show_mesh || show_aabb);
22670
22671 // Draw wire-frame version of all triangles
22672 ImRect clip_rect = draw_cmd->ClipRect;
22673 ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
22674 ImDrawListFlags backup_flags = out_draw_list->Flags;
22675 out_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
22676 for (unsigned int idx_n = draw_cmd->IdxOffset, idx_end = draw_cmd->IdxOffset + draw_cmd->ElemCount; idx_n < idx_end; )
22677 {
22678 ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; // We don't hold on those pointers past iterations as ->AddPolyline() may invalidate them if out_draw_list==draw_list
22679 ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset;
22680
22681 ImVec2 triangle[3];
22682 for (int n = 0; n < 3; n++, idx_n++)
22683 vtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos));
22684 if (show_mesh)
22685 out_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); // In yellow: mesh triangles
22686 }
22687 // Draw bounding boxes
22688 if (show_aabb)
22689 {
22690 out_draw_list->AddRect(ImTrunc(clip_rect.Min), ImTrunc(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU
22691 out_draw_list->AddRect(ImTrunc(vtxs_rect.Min), ImTrunc(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles
22692 }
22693 out_draw_list->Flags = backup_flags;
22694}
22695
22696// [DEBUG] Compute mask of inputs with the same codepoint.
22697static int CalcFontGlyphSrcOverlapMask(ImFontAtlas* atlas, ImFont* font, unsigned int codepoint)
22698{
22699 int mask = 0, count = 0;
22700 for (int src_n = 0; src_n < font->Sources.Size; src_n++)
22701 {
22702 ImFontConfig* src = font->Sources[src_n];
22703 if (!(src->FontLoader ? src->FontLoader : atlas->FontLoader)->FontSrcContainsGlyph(atlas, src, (ImWchar)codepoint))
22704 continue;
22705 mask |= (1 << src_n);
22706 count++;
22707 }
22708 return count > 1 ? mask : 0;
22709}
22710
22711// [DEBUG] Display details for a single font, called by ShowStyleEditor().
22713{
22714 ImGuiContext& g = *GImGui;
22716 ImFontAtlas* atlas = font->ContainerAtlas;
22717 bool opened = TreeNode(font, "Font: \"%s\": %d sources(s)", font->GetDebugName(), font->Sources.Size);
22718
22719 // Display preview text
22720 if (!opened)
22721 Indent();
22722 Indent();
22723 if (cfg->ShowFontPreview)
22724 {
22725 PushFont(font, 0.0f);
22726 Text("The quick brown fox jumps over the lazy dog");
22727 PopFont();
22728 }
22729 if (!opened)
22730 {
22731 Unindent();
22732 Unindent();
22733 return;
22734 }
22735 if (SmallButton("Set as default"))
22736 GetIO().FontDefault = font;
22737 SameLine();
22738 BeginDisabled(atlas->Fonts.Size <= 1 || atlas->Locked);
22739 if (SmallButton("Remove"))
22740 atlas->RemoveFont(font);
22741 EndDisabled();
22742 SameLine();
22743 if (SmallButton("Clear bakes"))
22744 ImFontAtlasFontDiscardBakes(atlas, font, 0);
22745 SameLine();
22746 if (SmallButton("Clear unused"))
22747 ImFontAtlasFontDiscardBakes(atlas, font, 2);
22748
22749 // Display details
22750#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
22752 DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f");
22753 /*SameLine(); MetricsHelpMarker(
22754 "Note that the default embedded font is NOT meant to be scaled.\n\n"
22755 "Font are currently rendered into bitmaps at a given size at the time of building the atlas. "
22756 "You may oversample them to get some flexibility with scaling. "
22757 "You can also render at multiple sizes and select which one to use at runtime.\n\n"
22758 "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)");*/
22759#endif
22760
22761 char c_str[5];
22762 Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar);
22763 Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar);
22764
22765 for (int src_n = 0; src_n < font->Sources.Size; src_n++)
22766 {
22767 ImFontConfig* src = font->Sources[src_n];
22768 if (TreeNode(src, "Input %d: \'%s\', Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)",
22769 src_n, src->Name, src->OversampleH, src->OversampleV, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y))
22770 {
22771 const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
22772 Text("Loader: '%s'", loader->Name ? loader->Name : "N/A");
22773#ifdef IMGUI_ENABLE_FREETYPE
22774 if (loader->Name != NULL && strcmp(loader->Name, "FreeType") == 0)
22775 {
22776 unsigned int loader_flags = src->FontLoaderFlags;
22777 Text("FreeType Loader Flags: 0x%08X", loader_flags);
22778 if (ImGuiFreeType::DebugEditFontLoaderFlags(&loader_flags))
22779 {
22780 ImFontAtlasFontDestroyOutput(atlas, font);
22781 src->FontLoaderFlags = loader_flags;
22782 ImFontAtlasFontInitOutput(atlas, font);
22783 }
22784 }
22785#endif
22786 TreePop();
22787 }
22788 }
22789 if (font->Sources.Size > 1 && TreeNode("Input Glyphs Overlap Detection Tool"))
22790 {
22791 TextWrapped("- First Input that contains the glyph is used.\n"
22792 "- Use ImFontConfig::GlyphExcludeRanges[] to specify ranges to ignore glyph in given Input.\n- Prefer using a small number of ranges as the list is scanned every time a new glyph is loaded,\n - e.g. GlyphExcludeRanges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };\n- This tool doesn't cache results and is slow, don't keep it open!");
22793 if (BeginTable("table", 2))
22794 {
22795 for (unsigned int c = 0; c < 0x10000; c++)
22796 if (int overlap_mask = CalcFontGlyphSrcOverlapMask(atlas, font, c))
22797 {
22798 unsigned int c_end = c + 1;
22799 while (c_end < 0x10000 && CalcFontGlyphSrcOverlapMask(atlas, font, c_end) == overlap_mask)
22800 c_end++;
22801 if (TableNextColumn() && TreeNode((void*)(intptr_t)c, "U+%04X-U+%04X: %d codepoints in %d inputs", c, c_end - 1, c_end - c, ImCountSetBits(overlap_mask)))
22802 {
22803 char utf8_buf[5];
22804 for (unsigned int n = c; n < c_end; n++)
22805 BulletText("Codepoint U+%04X (%s)", n, ImTextCharToUtf8(utf8_buf, n));
22806 TreePop();
22807 }
22809 for (int src_n = 0; src_n < font->Sources.Size; src_n++)
22810 if (overlap_mask & (1 << src_n))
22811 {
22812 Text("%d ", src_n);
22813 SameLine();
22814 }
22815 c = c_end - 1;
22816 }
22817 EndTable();
22818 }
22819 TreePop();
22820 }
22821
22822 // Display all glyphs of the fonts in separate pages of 256 characters
22823 for (int baked_n = 0; baked_n < atlas->Builder->BakedPool.Size; baked_n++)
22824 {
22825 ImFontBaked* baked = &atlas->Builder->BakedPool[baked_n];
22826 if (baked->ContainerFont != font)
22827 continue;
22828 PushID(baked_n);
22829 if (TreeNode("Glyphs", "Baked at { %.2fpx, d.%.2f }: %d glyphs%s", baked->Size, baked->RasterizerDensity, baked->Glyphs.Size, (baked->LastUsedFrame < atlas->Builder->FrameCount - 1) ? " *Unused*" : ""))
22830 {
22831 if (SmallButton("Load all"))
22832 for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base++)
22833 baked->FindGlyph((ImWchar)base);
22834
22835 const int surface_sqrt = (int)ImSqrt((float)baked->MetricsTotalSurface);
22836 Text("Ascent: %f, Descent: %f, Ascent-Descent: %f", baked->Ascent, baked->Descent, baked->Ascent - baked->Descent);
22837 Text("Texture Area: about %d px ~%dx%d px", baked->MetricsTotalSurface, surface_sqrt, surface_sqrt);
22838 for (int src_n = 0; src_n < font->Sources.Size; src_n++)
22839 {
22840 ImFontConfig* src = font->Sources[src_n];
22841 int oversample_h, oversample_v;
22842 ImFontAtlasBuildGetOversampleFactors(src, baked, &oversample_h, &oversample_v);
22843 BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)",
22844 src_n, src->Name, src->OversampleH, oversample_h, src->OversampleV, oversample_v, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y);
22845 }
22846
22847 DebugNodeFontGlyphesForSrcMask(font, baked, ~0);
22848 TreePop();
22849 }
22850 PopID();
22851 }
22852 TreePop();
22853 Unindent();
22854}
22855
22857{
22858 ImDrawList* draw_list = GetWindowDrawList();
22859 const ImU32 glyph_col = GetColorU32(ImGuiCol_Text);
22860 const float cell_size = baked->Size * 1;
22861 const float cell_spacing = GetStyle().ItemSpacing.y;
22862 for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
22863 {
22864 // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k)
22865 // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT
22866 // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here)
22867 if (!(base & 8191) && font->IsGlyphRangeUnused(base, base + 8191))
22868 {
22869 base += 8192 - 256;
22870 continue;
22871 }
22872
22873 int count = 0;
22874 for (unsigned int n = 0; n < 256; n++)
22875 if (const ImFontGlyph* glyph = baked->IsGlyphLoaded((ImWchar)(base + n)) ? baked->FindGlyph((ImWchar)(base + n)) : NULL)
22876 if (src_mask & (1 << glyph->SourceIdx))
22877 count++;
22878 if (count <= 0)
22879 continue;
22880 if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
22881 continue;
22882
22883 // Draw a 16x16 grid of glyphs
22884 ImVec2 base_pos = GetCursorScreenPos();
22885 for (unsigned int n = 0; n < 256; n++)
22886 {
22887 // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions
22888 // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string.
22889 ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
22890 ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
22891 const ImFontGlyph* glyph = baked->IsGlyphLoaded((ImWchar)(base + n)) ? baked->FindGlyph((ImWchar)(base + n)) : NULL;
22892 draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
22893 if (!glyph || (src_mask & (1 << glyph->SourceIdx)) == 0)
22894 continue;
22895 font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n));
22896 if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip())
22897 {
22898 DebugNodeFontGlyph(font, glyph);
22899 EndTooltip();
22900 }
22901 }
22902 Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
22903 TreePop();
22904 }
22905}
22906
22908{
22909 Text("Codepoint: U+%04X", glyph->Codepoint);
22910 Separator();
22911 Text("Visible: %d", glyph->Visible);
22912 Text("AdvanceX: %.1f", glyph->AdvanceX);
22913 Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
22914 Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
22915 if (glyph->PackId >= 0)
22916 {
22918 Text("PackId: %d (%dx%d rect at %d,%d)", glyph->PackId, r->w, r->h, r->x, r->y);
22919 }
22920 Text("SourceIdx: %d", glyph->SourceIdx);
22921}
22922
22923// [DEBUG] Display contents of ImGuiStorage
22924void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)
22925{
22926 if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
22927 return;
22928 for (const ImGuiStoragePair& p : storage->Data)
22929 {
22930 BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer.
22932 }
22933 TreePop();
22934}
22935
22936// [DEBUG] Display contents of ImGuiTabBar
22937void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)
22938{
22939 // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings.
22940 char buf[256];
22941 char* p = buf;
22942 const char* buf_end = buf + IM_ARRAYSIZE(buf);
22943 const bool is_active = (tab_bar->PrevFrameVisible >= GetFrameCount() - 2);
22944 p += ImFormatString(p, buf_end - p, "%s 0x%08X (%d tabs)%s {", label, tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*");
22945 for (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++)
22946 {
22947 ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
22948 p += ImFormatString(p, buf_end - p, "%s'%s'", tab_n > 0 ? ", " : "", TabBarGetTabName(tab_bar, tab));
22949 }
22950 p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } ");
22952 bool open = TreeNode(label, "%s", buf);
22953 if (!is_active) { PopStyleColor(); }
22954 if (is_active && IsItemHovered())
22955 {
22956 ImDrawList* draw_list = GetForegroundDrawList();
22957 draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255));
22958 draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
22959 draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
22960 }
22961 if (open)
22962 {
22963 for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
22964 {
22965 ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
22966 PushID(tab);
22967 if (SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2);
22968 if (SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine();
22969 Text("%02d%c Tab 0x%08X '%s' Offset: %.2f, Width: %.2f/%.2f",
22970 tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, TabBarGetTabName(tab_bar, tab), tab->Offset, tab->Width, tab->ContentWidth);
22971 PopID();
22972 }
22973 TreePop();
22974 }
22975}
22976
22978{
22979 ImGuiContext& g = *GImGui;
22981 bool open = TreeNode((void*)(intptr_t)viewport->ID, "Viewport #%d, ID: 0x%08X, Parent: 0x%08X, Window: \"%s\"", viewport->Idx, viewport->ID, viewport->ParentViewportId, viewport->Window ? viewport->Window->Name : "N/A");
22982 if (IsItemHovered())
22984 if (open)
22985 {
22986 ImGuiWindowFlags flags = viewport->Flags;
22987 BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nFrameBufferScale: (%.2f,%.2f)\nWorkArea Inset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f\nMonitor: %d, DpiScale: %.0f%%",
22988 viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y,
22989 viewport->FramebufferScale.x, viewport->FramebufferScale.y,
22990 viewport->WorkInsetMin.x, viewport->WorkInsetMin.y, viewport->WorkInsetMax.x, viewport->WorkInsetMax.y,
22991 viewport->PlatformMonitor, viewport->DpiScale * 100.0f);
22992 if (viewport->Idx > 0) { SameLine(); if (SmallButton("Reset Pos")) { viewport->Pos = ImVec2(200, 200); viewport->UpdateWorkRect(); if (viewport->Window) viewport->Window->Pos = viewport->Pos; } }
22993 BulletText("Flags: 0x%04X =%s%s%s%s%s%s%s%s%s%s%s%s%s", viewport->Flags,
22994 //(flags & ImGuiViewportFlags_IsPlatformWindow) ? " IsPlatformWindow" : "", // Omitting because it is the standard
22995 (flags & ImGuiViewportFlags_IsPlatformMonitor) ? " IsPlatformMonitor" : "",
22996 (flags & ImGuiViewportFlags_IsMinimized) ? " IsMinimized" : "",
22997 (flags & ImGuiViewportFlags_IsFocused) ? " IsFocused" : "",
22998 (flags & ImGuiViewportFlags_OwnedByApp) ? " OwnedByApp" : "",
22999 (flags & ImGuiViewportFlags_NoDecoration) ? " NoDecoration" : "",
23000 (flags & ImGuiViewportFlags_NoTaskBarIcon) ? " NoTaskBarIcon" : "",
23001 (flags & ImGuiViewportFlags_NoFocusOnAppearing) ? " NoFocusOnAppearing" : "",
23002 (flags & ImGuiViewportFlags_NoFocusOnClick) ? " NoFocusOnClick" : "",
23003 (flags & ImGuiViewportFlags_NoInputs) ? " NoInputs" : "",
23004 (flags & ImGuiViewportFlags_NoRendererClear) ? " NoRendererClear" : "",
23005 (flags & ImGuiViewportFlags_NoAutoMerge) ? " NoAutoMerge" : "",
23006 (flags & ImGuiViewportFlags_TopMost) ? " TopMost" : "",
23007 (flags & ImGuiViewportFlags_CanHostOtherWindows) ? " CanHostOtherWindows" : "");
23008 for (ImDrawList* draw_list : viewport->DrawDataP.CmdLists)
23009 DebugNodeDrawList(NULL, viewport, draw_list, "DrawList");
23010 TreePop();
23011 }
23012}
23013
23014void ImGui::DebugNodePlatformMonitor(ImGuiPlatformMonitor* monitor, const char* label, int idx)
23015{
23016 BulletText("%s %d: DPI %.0f%%\n MainMin (%.0f,%.0f), MainMax (%.0f,%.0f), MainSize (%.0f,%.0f)\n WorkMin (%.0f,%.0f), WorkMax (%.0f,%.0f), WorkSize (%.0f,%.0f)",
23017 label, idx, monitor->DpiScale * 100.0f,
23018 monitor->MainPos.x, monitor->MainPos.y, monitor->MainPos.x + monitor->MainSize.x, monitor->MainPos.y + monitor->MainSize.y, monitor->MainSize.x, monitor->MainSize.y,
23019 monitor->WorkPos.x, monitor->WorkPos.y, monitor->WorkPos.x + monitor->WorkSize.x, monitor->WorkPos.y + monitor->WorkSize.y, monitor->WorkSize.x, monitor->WorkSize.y);
23020}
23021
23022void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
23023{
23024 if (window == NULL)
23025 {
23026 BulletText("%s: NULL", label);
23027 return;
23028 }
23029
23030 ImGuiContext& g = *GImGui;
23031 const bool is_active = window->WasActive;
23034 const bool open = TreeNodeEx(label, tree_node_flags, "%s '%s'%s", label, window->Name, is_active ? "" : " *Inactive*");
23035 if (!is_active) { PopStyleColor(); }
23036 if (IsItemHovered() && is_active)
23037 GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
23038 if (!open)
23039 return;
23040
23041 if (window->MemoryCompacted)
23042 TextDisabled("Note: some memory buffers have been compacted/freed.");
23043
23044 if (g.IO.ConfigDebugIsDebuggerPresent && DebugBreakButton("**DebugBreak**", "in Begin()"))
23045 g.DebugBreakInWindow = window->ID;
23046
23047 ImGuiWindowFlags flags = window->Flags;
23048 DebugNodeDrawList(window, window->Viewport, window->DrawList, "DrawList");
23049 BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f) Ideal (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y, window->ContentSizeIdeal.x, window->ContentSizeIdeal.y);
23050 BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags,
23051 (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
23052 (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
23053 (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
23054 if (flags & ImGuiWindowFlags_ChildWindow)
23055 BulletText("ChildFlags: 0x%08X (%s%s%s%s..)", window->ChildFlags,
23056 (window->ChildFlags & ImGuiChildFlags_Borders) ? "Borders " : "",
23057 (window->ChildFlags & ImGuiChildFlags_ResizeX) ? "ResizeX " : "",
23058 (window->ChildFlags & ImGuiChildFlags_ResizeY) ? "ResizeY " : "",
23059 (window->ChildFlags & ImGuiChildFlags_NavFlattened) ? "NavFlattened " : "");
23060 BulletText("WindowClassId: 0x%08X", window->WindowClass.ClassId);
23061 BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : "");
23062 BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
23063 BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
23064 for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++)
23065 {
23066 ImRect r = window->NavRectRel[layer];
23067 if (r.Min.x >= r.Max.x && r.Min.y >= r.Max.y)
23068 BulletText("NavLastIds[%d]: 0x%08X", layer, window->NavLastIds[layer]);
23069 else
23070 BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y);
23071 DebugLocateItemOnHover(window->NavLastIds[layer]);
23072 }
23073 const ImVec2* pr = window->NavPreferredScoringPosRel;
23074 for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++)
23075 BulletText("NavPreferredScoringPosRel[%d] = {%.1f,%.1f)", layer, (pr[layer].x == FLT_MAX ? -99999.0f : pr[layer].x), (pr[layer].y == FLT_MAX ? -99999.0f : pr[layer].y)); // Display as 99999.0f so it looks neater.
23076 BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
23077
23078 BulletText("Viewport: %d%s, ViewportId: 0x%08X, ViewportPos: (%.1f,%.1f)", window->Viewport ? window->Viewport->Idx : -1, window->ViewportOwned ? " (Owned)" : "", window->ViewportId, window->ViewportPos.x, window->ViewportPos.y);
23079 BulletText("ViewportMonitor: %d", window->Viewport ? window->Viewport->PlatformMonitor : -1);
23080 BulletText("DockId: 0x%04X, DockOrder: %d, Act: %d, Vis: %d", window->DockId, window->DockOrder, window->DockIsActive, window->DockTabIsVisible);
23081 if (window->DockNode || window->DockNodeAsHost)
23082 DebugNodeDockNode(window->DockNodeAsHost ? window->DockNodeAsHost : window->DockNode, window->DockNodeAsHost ? "DockNodeAsHost" : "DockNode");
23083
23084 if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); }
23085 if (window->RootWindowDockTree != window->RootWindow) { DebugNodeWindow(window->RootWindowDockTree, "RootWindowDockTree"); }
23086 if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); }
23087 if (window->ParentWindowForFocusRoute != NULL) { DebugNodeWindow(window->ParentWindowForFocusRoute, "ParentWindowForFocusRoute"); }
23088 if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); }
23089 if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
23090 {
23091 for (ImGuiOldColumns& columns : window->ColumnsStorage)
23092 DebugNodeColumns(&columns);
23093 TreePop();
23094 }
23095 DebugNodeStorage(&window->StateStorage, "Storage");
23096 TreePop();
23097}
23098
23100{
23101 if (settings->WantDelete)
23102 BeginDisabled();
23103 Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d",
23104 settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed);
23105 if (settings->WantDelete)
23106 EndDisabled();
23107}
23108
23110{
23111 if (!TreeNode(label, "%s (%d)", label, windows->Size))
23112 return;
23113 for (int i = windows->Size - 1; i >= 0; i--) // Iterate front to back
23114 {
23115 PushID((*windows)[i]);
23116 DebugNodeWindow((*windows)[i], "Window");
23117 PopID();
23118 }
23119 TreePop();
23120}
23121
23122// FIXME-OPT: This is technically suboptimal, but it is simpler this way.
23123void ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack)
23124{
23125 for (int i = 0; i < windows_size; i++)
23126 {
23127 ImGuiWindow* window = windows[i];
23128 if (window->ParentWindowInBeginStack != parent_in_begin_stack)
23129 continue;
23130 char buf[20];
23131 ImFormatString(buf, IM_ARRAYSIZE(buf), "[%04d] Window", window->BeginOrderWithinContext);
23132 //BulletText("[%04d] Window '%s'", window->BeginOrderWithinContext, window->Name);
23133 DebugNodeWindow(window, buf);
23134 TreePush(buf);
23135 DebugNodeWindowsListByBeginStackParent(windows + i + 1, windows_size - i - 1, window);
23136 TreePop();
23137 }
23138}
23139
23140//-----------------------------------------------------------------------------
23141// [SECTION] DEBUG LOG WINDOW
23142//-----------------------------------------------------------------------------
23143
23144void ImGui::DebugLog(const char* fmt, ...)
23145{
23146 va_list args;
23147 va_start(args, fmt);
23148 DebugLogV(fmt, args);
23149 va_end(args);
23150}
23151
23152void ImGui::DebugLogV(const char* fmt, va_list args)
23153{
23154 ImGuiContext& g = *GImGui;
23155 const int old_size = g.DebugLogBuf.size();
23156 if (g.ContextName[0] != 0)
23157 g.DebugLogBuf.appendf("[%s] [%05d] ", g.ContextName, g.FrameCount);
23158 else
23159 g.DebugLogBuf.appendf("[%05d] ", g.FrameCount);
23160 g.DebugLogBuf.appendfv(fmt, args);
23161 g.DebugLogIndex.append(g.DebugLogBuf.c_str(), old_size, g.DebugLogBuf.size());
23163 IMGUI_DEBUG_PRINTF("%s", g.DebugLogBuf.begin() + old_size);
23164#ifdef IMGUI_ENABLE_TEST_ENGINE
23165 // IMGUI_TEST_ENGINE_LOG() adds a trailing \n automatically
23166 const int new_size = g.DebugLogBuf.size();
23167 const bool trailing_carriage_return = (g.DebugLogBuf[new_size - 1] == '\n');
23169 IMGUI_TEST_ENGINE_LOG("%.*s", new_size - old_size - (trailing_carriage_return ? 1 : 0), g.DebugLogBuf.begin() + old_size);
23170#endif
23171}
23172
23173// FIXME-LAYOUT: To be done automatically via layout mode once we rework ItemSize/ItemAdd into ItemLayout.
23174static void SameLineOrWrap(const ImVec2& size)
23175{
23176 ImGuiContext& g = *GImGui;
23177 ImGuiWindow* window = g.CurrentWindow;
23178 ImVec2 pos(window->DC.CursorPosPrevLine.x + g.Style.ItemSpacing.x, window->DC.CursorPosPrevLine.y);
23179 if (window->WorkRect.Contains(ImRect(pos, pos + size)))
23181}
23182
23183static void ShowDebugLogFlag(const char* name, ImGuiDebugLogFlags flags)
23184{
23185 ImGuiContext& g = *GImGui;
23187 SameLineOrWrap(size); // FIXME-LAYOUT: To be done automatically once we rework ItemSize/ItemAdd into ItemLayout.
23188
23189 bool highlight_errors = (flags == ImGuiDebugLogFlags_EventError && g.DebugLogSkippedErrors > 0);
23190 if (highlight_errors)
23191 ImGui::PushStyleColor(ImGuiCol_Text, ImLerp(g.Style.Colors[ImGuiCol_Text], ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 0.30f));
23192 if (ImGui::CheckboxFlags(name, &g.DebugLogFlags, flags) && g.IO.KeyShift && (g.DebugLogFlags & flags) != 0)
23193 {
23195 g.DebugLogAutoDisableFlags |= flags;
23196 }
23197 if (highlight_errors)
23198 {
23200 ImGui::SetItemTooltip("%d past errors skipped.", g.DebugLogSkippedErrors);
23201 }
23202 else
23203 {
23204 ImGui::SetItemTooltip("Hold SHIFT when clicking to enable for 2 frames only (useful for spammy log entries)");
23205 }
23206}
23207
23209{
23210 ImGuiContext& g = *GImGui;
23213 if (!Begin("Dear ImGui Debug Log", p_open) || GetCurrentWindow()->BeginCount > 1)
23214 {
23215 End();
23216 return;
23217 }
23218
23219 ImGuiDebugLogFlags all_enable_flags = ImGuiDebugLogFlags_EventMask_ & ~ImGuiDebugLogFlags_EventInputRouting;
23220 CheckboxFlags("All", &g.DebugLogFlags, all_enable_flags);
23221 SetItemTooltip("(except InputRouting which is spammy)");
23222
23235
23236 if (SmallButton("Clear"))
23237 {
23238 g.DebugLogBuf.clear();
23239 g.DebugLogIndex.clear();
23241 }
23242 SameLine();
23243 if (SmallButton("Copy"))
23245 SameLine();
23246 if (SmallButton("Configure Outputs.."))
23247 OpenPopup("Outputs");
23248 if (BeginPopup("Outputs"))
23249 {
23251#ifndef IMGUI_ENABLE_TEST_ENGINE
23252 BeginDisabled();
23253#endif
23255#ifndef IMGUI_ENABLE_TEST_ENGINE
23256 EndDisabled();
23257#endif
23258 EndPopup();
23259 }
23260
23262
23263 const ImGuiDebugLogFlags backup_log_flags = g.DebugLogFlags;
23264 g.DebugLogFlags &= ~ImGuiDebugLogFlags_EventClipper;
23265
23266 ImGuiListClipper clipper;
23267 clipper.Begin(g.DebugLogIndex.size());
23268 while (clipper.Step())
23269 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
23271 g.DebugLogFlags = backup_log_flags;
23272 if (GetScrollY() >= GetScrollMaxY())
23273 SetScrollHereY(1.0f);
23274 EndChild();
23275
23276 End();
23277}
23278
23279// Display line, search for 0xXXXXXXXX identifiers and call DebugLocateItemOnHover() when hovered.
23280void ImGui::DebugTextUnformattedWithLocateItem(const char* line_begin, const char* line_end)
23281{
23282 TextUnformatted(line_begin, line_end);
23284 return;
23285 ImGuiContext& g = *GImGui;
23286 ImRect text_rect = g.LastItemData.Rect;
23287 for (const char* p = line_begin; p <= line_end - 10; p++)
23288 {
23289 ImGuiID id = 0;
23290 if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1 || ImCharIsXdigitA(p[10]))
23291 continue;
23292 ImVec2 p0 = CalcTextSize(line_begin, p);
23293 ImVec2 p1 = CalcTextSize(p, p + 10);
23294 g.LastItemData.Rect = ImRect(text_rect.Min + ImVec2(p0.x, 0.0f), text_rect.Min + ImVec2(p0.x + p1.x, p1.y));
23297 p += 10;
23298 }
23299}
23300
23301//-----------------------------------------------------------------------------
23302// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, ID STACK TOOL)
23303//-----------------------------------------------------------------------------
23304
23305// Draw a small cross at current CursorPos in current window's DrawList
23307{
23308 ImGuiContext& g = *GImGui;
23309 ImGuiWindow* window = g.CurrentWindow;
23310 ImVec2 pos = window->DC.CursorPos;
23311 window->DrawList->AddLine(ImVec2(pos.x, pos.y - 3.0f), ImVec2(pos.x, pos.y + 4.0f), col, 1.0f);
23312 window->DrawList->AddLine(ImVec2(pos.x - 3.0f, pos.y), ImVec2(pos.x + 4.0f, pos.y), col, 1.0f);
23313}
23314
23315// Draw a 10px wide rectangle around CurposPos.x using Line Y1/Y2 in current window's DrawList
23317{
23318 ImGuiContext& g = *GImGui;
23319 ImGuiWindow* window = g.CurrentWindow;
23320 float curr_x = window->DC.CursorPos.x;
23321 float line_y1 = (window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y);
23322 float line_y2 = line_y1 + (window->DC.IsSameLine ? window->DC.PrevLineSize.y : window->DC.CurrLineSize.y);
23323 window->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y1), ImVec2(curr_x + 5.0f, line_y1), col, 1.0f);
23324 window->DrawList->AddLine(ImVec2(curr_x - 0.5f, line_y1), ImVec2(curr_x - 0.5f, line_y2), col, 1.0f);
23325 window->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y2), ImVec2(curr_x + 5.0f, line_y2), col, 1.0f);
23326}
23327
23328// Draw last item rect in ForegroundDrawList (so it is always visible)
23330{
23331 ImGuiContext& g = *GImGui;
23332 ImGuiWindow* window = g.CurrentWindow;
23334}
23335
23336// [DEBUG] Locate item position/rectangle given an ID.
23337static const ImU32 DEBUG_LOCATE_ITEM_COLOR = IM_COL32(0, 255, 0, 255); // Green
23338
23340{
23341 ImGuiContext& g = *GImGui;
23342 g.DebugLocateId = target_id;
23343 g.DebugLocateFrames = 2;
23344 g.DebugBreakInLocateId = false;
23345}
23346
23347// FIXME: Doesn't work over through a modal window, because they clear HoveredWindow.
23349{
23351 return;
23352 ImGuiContext& g = *GImGui;
23353 DebugLocateItem(target_id);
23355
23356 // Can't easily use a context menu here because it will mess with focus, active id etc.
23358 {
23359 DebugBreakButtonTooltip(false, "in ItemAdd()");
23361 g.DebugBreakInLocateId = true;
23362 }
23363}
23364
23366{
23367 ImGuiContext& g = *GImGui;
23368
23369 // [DEBUG] Debug break requested by user
23372
23373 ImGuiLastItemData item_data = g.LastItemData;
23374 g.DebugLocateId = 0;
23376 ImRect r = item_data.Rect;
23377 r.Expand(3.0f);
23378 ImVec2 p1 = g.IO.MousePos;
23379 ImVec2 p2 = ImVec2((p1.x < r.Min.x) ? r.Min.x : (p1.x > r.Max.x) ? r.Max.x : p1.x, (p1.y < r.Min.y) ? r.Min.y : (p1.y > r.Max.y) ? r.Max.y : p1.y);
23380 draw_list->AddRect(r.Min, r.Max, DEBUG_LOCATE_ITEM_COLOR);
23381 draw_list->AddLine(p1, p2, DEBUG_LOCATE_ITEM_COLOR);
23382}
23383
23385{
23386 ImGuiContext& g = *GImGui;
23387 g.DebugItemPickerActive = true;
23388}
23389
23390// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
23392{
23393 ImGuiContext& g = *GImGui;
23395 if (!g.DebugItemPickerActive)
23396 return;
23397
23398 const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
23401 g.DebugItemPickerActive = false;
23402 const bool change_mapping = g.IO.KeyMods == (ImGuiMod_Ctrl | ImGuiMod_Shift);
23403 if (!change_mapping && IsMouseClicked(g.DebugItemPickerMouseButton) && hovered_id)
23404 {
23405 g.DebugItemPickerBreakId = hovered_id;
23406 g.DebugItemPickerActive = false;
23407 }
23408 for (int mouse_button = 0; mouse_button < 3; mouse_button++)
23409 if (change_mapping && IsMouseClicked(mouse_button))
23410 g.DebugItemPickerMouseButton = (ImU8)mouse_button;
23411 SetNextWindowBgAlpha(0.70f);
23412 if (!BeginTooltip())
23413 return;
23414 Text("HoveredId: 0x%08X", hovered_id);
23415 Text("Press ESC to abort picking.");
23416 const char* mouse_button_names[] = { "Left", "Right", "Middle" };
23417 if (change_mapping)
23418 Text("Remap w/ Ctrl+Shift: click anywhere to select new mouse button.");
23419 else
23420 TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click %s Button to break in debugger! (remap w/ Ctrl+Shift)", mouse_button_names[g.DebugItemPickerMouseButton]);
23421 EndTooltip();
23422}
23423
23424// [DEBUG] ID Stack Tool: update queries. Called by NewFrame()
23426{
23427 ImGuiContext& g = *GImGui;
23429
23430 // Clear hook when id stack tool is not visible
23431 g.DebugHookIdInfo = 0;
23432 if (g.FrameCount != tool->LastActiveFrame + 1)
23433 return;
23434
23435 // Update queries. The steps are: -1: query Stack, >= 0: query each stack item
23436 // We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time
23438 if (tool->QueryId != query_id)
23439 {
23440 tool->QueryId = query_id;
23441 tool->StackLevel = -1;
23442 tool->Results.resize(0);
23443 }
23444 if (query_id == 0)
23445 return;
23446
23447 // Advance to next stack level when we got our result, or after 2 frames (in case we never get a result)
23448 int stack_level = tool->StackLevel;
23449 if (stack_level >= 0 && stack_level < tool->Results.Size)
23450 if (tool->Results[stack_level].QuerySuccess || tool->Results[stack_level].QueryFrameCount > 2)
23451 tool->StackLevel++;
23452
23453 // Update hook
23454 stack_level = tool->StackLevel;
23455 if (stack_level == -1)
23456 g.DebugHookIdInfo = query_id;
23457 if (stack_level >= 0 && stack_level < tool->Results.Size)
23458 {
23459 g.DebugHookIdInfo = tool->Results[stack_level].ID;
23460 tool->Results[stack_level].QueryFrameCount++;
23461 }
23462}
23463
23464// [DEBUG] ID Stack tool: hooks called by GetID() family functions
23465void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end)
23466{
23467 ImGuiContext& g = *GImGui;
23468 ImGuiWindow* window = g.CurrentWindow;
23470
23471 // Step 0: stack query
23472 // This assumes that the ID was computed with the current ID stack, which tends to be the case for our widget.
23473 if (tool->StackLevel == -1)
23474 {
23475 tool->StackLevel++;
23476 tool->Results.resize(window->IDStack.Size + 1, ImGuiStackLevelInfo());
23477 for (int n = 0; n < window->IDStack.Size + 1; n++)
23478 tool->Results[n].ID = (n < window->IDStack.Size) ? window->IDStack[n] : id;
23479 return;
23480 }
23481
23482 // Step 1+: query for individual level
23483 IM_ASSERT(tool->StackLevel >= 0);
23484 if (tool->StackLevel != window->IDStack.Size)
23485 return;
23486 ImGuiStackLevelInfo* info = &tool->Results[tool->StackLevel];
23487 IM_ASSERT(info->ID == id && info->QueryFrameCount > 0);
23488
23489 switch (data_type)
23490 {
23491 case ImGuiDataType_S32:
23492 ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%d", (int)(intptr_t)data_id);
23493 break;
23495 ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%.*s", data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)ImStrlen((const char*)data_id), (const char*)data_id);
23496 break;
23498 ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "(void*)0x%p", data_id);
23499 break;
23500 case ImGuiDataType_ID:
23501 if (info->Desc[0] != 0) // PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one.
23502 return;
23503 ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "0x%08X [override]", id);
23504 break;
23505 default:
23506 IM_ASSERT(0);
23507 }
23508 info->QuerySuccess = true;
23509 info->DataType = data_type;
23510}
23511
23512static int StackToolFormatLevelInfo(ImGuiIDStackTool* tool, int n, bool format_for_ui, char* buf, size_t buf_size)
23513{
23514 ImGuiStackLevelInfo* info = &tool->Results[n];
23515 ImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? ImGui::FindWindowByID(info->ID) : NULL;
23516 if (window) // Source: window name (because the root ID don't call GetID() and so doesn't get hooked)
23517 return ImFormatString(buf, buf_size, format_for_ui ? "\"%s\" [window]" : "%s", window->Name);
23518 if (info->QuerySuccess) // Source: GetID() hooks (prioritize over ItemInfo() because we frequently use patterns like: PushID(str), Button("") where they both have same id)
23519 return ImFormatString(buf, buf_size, (format_for_ui && info->DataType == ImGuiDataType_String) ? "\"%s\"" : "%s", info->Desc);
23520 if (tool->StackLevel < tool->Results.Size) // Only start using fallback below when all queries are done, so during queries we don't flickering ??? markers.
23521 return (*buf = 0);
23522#ifdef IMGUI_ENABLE_TEST_ENGINE
23523 if (const char* label = ImGuiTestEngine_FindItemDebugLabel(GImGui, info->ID)) // Source: ImGuiTestEngine's ItemInfo()
23524 return ImFormatString(buf, buf_size, format_for_ui ? "??? \"%s\"" : "%s", label);
23525#endif
23526 return ImFormatString(buf, buf_size, "???");
23527}
23528
23529// ID Stack Tool: Display UI
23531{
23532 ImGuiContext& g = *GImGui;
23535 if (!Begin("Dear ImGui ID Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1)
23536 {
23537 End();
23538 return;
23539 }
23540
23541 // Display hovered/active status
23543
23544 // Build and display path
23545 tool->ResultPathBuf.resize(0);
23546 for (int stack_n = 0; stack_n < tool->Results.Size; stack_n++)
23547 {
23548 char level_desc[256];
23549 StackToolFormatLevelInfo(tool, stack_n, false, level_desc, IM_ARRAYSIZE(level_desc));
23550 tool->ResultPathBuf.append(stack_n == 0 ? "//" : "/");
23551 for (int n = 0; level_desc[n]; n++)
23552 {
23553 if (level_desc[n] == '/')
23554 tool->ResultPathBuf.append("\\");
23555 tool->ResultPathBuf.append(level_desc + n, level_desc + n + 1);
23556 }
23557 }
23558 Text("0x%08X", tool->QueryId);
23559 SameLine();
23560 MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details.");
23561
23562 // CTRL+C to copy path
23563 const float time_since_copy = (float)g.Time - tool->CopyToClipboardLastTime;
23564 SameLine();
23566 SameLine();
23567 TextColored((time_since_copy >= 0.0f && time_since_copy < 0.75f && ImFmod(time_since_copy, 0.25f) < 0.25f * 0.5f) ? ImVec4(1.f, 1.f, 0.3f, 1.f) : ImVec4(), "*COPIED*");
23569 {
23570 tool->CopyToClipboardLastTime = (float)g.Time;
23572 }
23573
23574 Text("- Path \"%s\"", tool->ResultPathBuf.c_str());
23575#ifdef IMGUI_ENABLE_TEST_ENGINE
23576 Text("- Label \"%s\"", tool->QueryId ? ImGuiTestEngine_FindItemDebugLabel(&g, tool->QueryId) : "");
23577#endif
23578
23579 Separator();
23580
23581 // Display decorated stack
23582 tool->LastActiveFrame = g.FrameCount;
23583 if (tool->Results.Size > 0 && BeginTable("##table", 3, ImGuiTableFlags_Borders))
23584 {
23585 const float id_width = CalcTextSize("0xDDDDDDDD").x;
23590 for (int n = 0; n < tool->Results.Size; n++)
23591 {
23592 ImGuiStackLevelInfo* info = &tool->Results[n];
23594 Text("0x%08X", (n > 0) ? tool->Results[n - 1].ID : 0);
23599 Text("0x%08X", info->ID);
23600 if (n == tool->Results.Size - 1)
23602 }
23603 EndTable();
23604 }
23605 End();
23606}
23607
23608#else
23609
23610void ImGui::ShowMetricsWindow(bool*) {}
23613void ImGui::DebugNodeDrawList(ImGuiWindow*, ImGuiViewportP*, const ImDrawList*, const char*) {}
23617void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {}
23618void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {}
23619void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {}
23623
23624void ImGui::ShowDebugLogWindow(bool*) {}
23625void ImGui::ShowIDStackToolWindow(bool*) {}
23627void ImGui::DebugHookIdInfo(ImGuiID, ImGuiDataType, const void*, const void*) {}
23628
23629#endif // #ifndef IMGUI_DISABLE_DEBUG_TOOLS
23630
23631#if !defined(IMGUI_DISABLE_DEMO_WINDOWS) || !defined(IMGUI_DISABLE_DEBUG_TOOLS)
23632// Demo helper function to select among loaded fonts.
23633// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one.
23634void ImGui::ShowFontSelector(const char* label)
23635{
23636 ImGuiIO& io = GetIO();
23637 ImFont* font_current = GetFont();
23638 if (BeginCombo(label, font_current->GetDebugName()))
23639 {
23640 for (ImFont* font : io.Fonts->Fonts)
23641 {
23642 PushID((void*)font);
23643 if (Selectable(font->GetDebugName(), font == font_current))
23644 io.FontDefault = font;
23645 if (font == font_current)
23647 PopID();
23648 }
23649 EndCombo();
23650 }
23651 SameLine();
23654 "- Load additional fonts with io.Fonts->AddFontXXX() functions.\n"
23655 "- Read FAQ and docs/FONTS.md for more details.");
23656 else
23658 "- Load additional fonts with io.Fonts->AddFontXXX() functions.\n"
23659 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
23660 "- Read FAQ and docs/FONTS.md for more details.\n"
23661 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
23662}
23663#endif // #if !defined(IMGUI_DISABLE_DEMO_WINDOWS) || !defined(IMGUI_DISABLE_DEBUG_TOOLS)
23664
23665//-----------------------------------------------------------------------------
23666
23667// Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.
23668// Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github.
23669#ifdef IMGUI_INCLUDE_IMGUI_USER_INL
23670#include "imgui_user.inl"
23671#endif
23672
23673//-----------------------------------------------------------------------------
23674
23675#endif // #ifndef IMGUI_DISABLE
struct HWND__ * HWND
long LONG
Definition: InputConfig.h:3
static ImGuiWindow * FindWindowNavFocusable(int i_start, int i_stop, int dir)
Definition: imgui.cpp:14783
const char * ImStreolRange(const char *str, const char *str_end)
Definition: imgui.cpp:2167
char * ImStrdupcpy(char *dst, size_t *p_dst_size, const char *src)
Definition: imgui.cpp:2138
static const char * GetMouseSourceName(ImGuiMouseSource source)
Definition: imgui.cpp:10757
static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow *window)
Definition: imgui.cpp:12169
static int GetWindowDisplayLayer(ImGuiWindow *window)
Definition: imgui.cpp:5829
const char * ImStrbol(const char *buf_mid_line, const char *buf_begin)
Definition: imgui.cpp:2173
static bool IsKeyChordPotentiallyCharInput(ImGuiKeyChord key_chord)
Definition: imgui.cpp:10016
static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow *window, const ImVec2 &size_desired)
Definition: imgui.cpp:6804
static void InitViewportDrawData(ImGuiViewportP *viewport)
Definition: imgui.cpp:5858
static bool IsWindowActiveAndVisible(ImGuiWindow *window)
Definition: imgui.cpp:5354
static int ImTextCharToUtf8_inline(char *buf, int buf_size, unsigned int c)
Definition: imgui.cpp:2612
static ImGuiWindow * FindBestWheelingWindow(const ImVec2 &wheel)
Definition: imgui.cpp:10610
static bool DockNodeIsDropAllowedOne(ImGuiWindow *payload, ImGuiWindow *host_window)
Definition: imgui.cpp:19157
static const char * GetInputSourceName(ImGuiInputSource source)
Definition: imgui.cpp:10751
void * ImMemdup(const void *src, size_t size)
Definition: imgui.cpp:2132
#define va_copy(dest, src)
Definition: imgui.cpp:3059
static const float NAV_WINDOWING_HIGHLIGHT_DELAY
Definition: imgui.cpp:1248
static float NavScoreItemDistInterval(float cand_min, float cand_max, float curr_min, float curr_max)
Definition: imgui.cpp:13517
static void ApplyWindowSettings(ImGuiWindow *window, ImGuiWindowSettings *settings)
Definition: imgui.cpp:6697
char * ImStrdup(const char *str)
Definition: imgui.cpp:2125
static const char * Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext *ctx)
Definition: imgui.cpp:21181
static void WindowSettingsHandler_WriteAll(ImGuiContext *, ImGuiSettingsHandler *, ImGuiTextBuffer *buf)
Definition: imgui.cpp:16012
static int StackToolFormatLevelInfo(ImGuiIDStackTool *tool, int n, bool format_for_ui, char *buf, size_t buf_size)
Definition: imgui.cpp:23512
static ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy)
Definition: imgui.cpp:13510
ImGuiContext * GImGui
Definition: imgui.cpp:1388
static void ClampWindowPos(ImGuiWindow *window, const ImRect &visibility_rect)
Definition: imgui.cpp:7229
static void NavBiasScoringRect(ImRect &r, ImVec2 &preferred_pos_rel, ImGuiDir move_dir, ImGuiNavMoveFlags move_flags)
Definition: imgui.cpp:14287
int ImFormatStringV(char *buf, size_t buf_size, const char *fmt, va_list args)
Definition: imgui.cpp:2268
static ImGuiWindow * GetCombinedRootWindow(ImGuiWindow *window, bool popup_hierarchy, bool dock_hierarchy)
Definition: imgui.cpp:8707
static ImGuiKeyChord GetMergedModsFromKeys()
Definition: imgui.cpp:10435
static int IMGUI_CDECL DockNodeComparerDepthMostFirst(const void *lhs, const void *rhs)
Definition: imgui.cpp:17541
static const ImVec2 TOOLTIP_DEFAULT_OFFSET_MOUSE
Definition: imgui.cpp:1255
static void UpdateAliasKey(ImGuiKey key, bool v, float analog_value)
Definition: imgui.cpp:10426
static int CalcFontGlyphSrcOverlapMask(ImFontAtlas *atlas, ImFont *font, unsigned int codepoint)
Definition: imgui.cpp:22697
ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, const ImVec2 &p4, const ImVec2 &p, float tess_tol)
Definition: imgui.cpp:2039
static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext *ctx, ImGuiViewport *viewport, ImGuiPlatformImeData *data)
Definition: imgui.cpp:21293
static const ImGuiCol GWindowDockStyleColors[ImGuiWindowDockStyleCol_COUNT]
Definition: imgui.cpp:3538
static bool ImGuiListClipper_StepInternal(ImGuiListClipper *clipper)
Definition: imgui.cpp:3275
static ImGuiMemFreeFunc GImAllocatorFreeFunc
Definition: imgui.cpp:1402
static ImGuiWindow * CreateNewWindow(const char *name, ImGuiWindowFlags flags)
Definition: imgui.cpp:6746
static const ImGuiStyleVarInfo GStyleVarsInfo[]
Definition: imgui.cpp:3543
static void NavUpdateWindowingTarget(int focus_change_dir)
Definition: imgui.cpp:14792
static const float DOCKING_TRANSPARENT_PAYLOAD_ALPHA
Definition: imgui.cpp:1260
static void ScaleWindow(ImGuiWindow *window, float scale)
Definition: imgui.cpp:5345
ImGuiStoragePair * ImLowerBound(ImGuiStoragePair *in_begin, ImGuiStoragePair *in_end, ImGuiID key)
Definition: imgui.cpp:2818
static const ImGuiResizeGripDef resize_grip_def[4]
Definition: imgui.cpp:6945
void ImTriangleBarycentricCoords(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p, float &out_u, float &out_v, float &out_w)
Definition: imgui.cpp:2070
static void * GImAllocatorUserData
Definition: imgui.cpp:1403
static int IMGUI_CDECL ChildWindowComparer(const void *lhs, const void *rhs)
Definition: imgui.cpp:5788
static float CalcDelayFromHoveredFlags(ImGuiHoveredFlags flags)
Definition: imgui.cpp:4739
static ImGuiDockNode * DockBuilderCopyNodeRec(ImGuiDockNode *src_node, ImGuiID dst_node_id_if_known, ImVector< ImGuiID > *out_node_remap_pairs)
Definition: imgui.cpp:20364
static void FlattenDrawDataIntoSingleLayer(ImDrawDataBuilder *builder)
Definition: imgui.cpp:5840
static void WindowSettingsHandler_ApplyAll(ImGuiContext *, ImGuiSettingsHandler *)
Definition: imgui.cpp:16000
void ImFormatStringToTempBuffer(const char **out_buf, const char **out_buf_end, const char *fmt,...)
Definition: imgui.cpp:2284
int ImTextStrToUtf8(char *out_buf, int out_buf_size, const ImWchar *in_text, const ImWchar *in_text_end)
Definition: imgui.cpp:2670
static void DockNodeHideWindowDuringHostWindowCreation(ImGuiWindow *window)
Definition: imgui.cpp:18031
static void DebugNodeDockNodeFlags(ImGuiDockNodeFlags *p_flags, const char *label, bool enabled)
Definition: imgui.cpp:22483
static ImGuiWindow * GetWindowForTitleAndMenuHeight(ImGuiWindow *window)
Definition: imgui.cpp:6775
static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_height)
Definition: imgui.cpp:3168
static ImGuiWindow * FindFrontMostVisibleChildWindow(ImGuiWindow *window)
Definition: imgui.cpp:5908
static void SetCurrentWindow(ImGuiWindow *window)
Definition: imgui.cpp:4541
static ImRect GetResizeBorderRect(ImGuiWindow *window, int border_n, float perp_padding, float thickness)
Definition: imgui.cpp:6968
static void InitOrLoadWindowSettings(ImGuiWindow *window, ImGuiWindowSettings *settings)
Definition: imgui.cpp:6714
static void LogTextV(ImGuiContext &g, const char *fmt, va_list args)
Definition: imgui.cpp:15452
int ImStrnicmp(const char *str1, const char *str2, size_t count)
Definition: imgui.cpp:2109
static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio)
Definition: imgui.cpp:12160
static void AddWindowToDrawData(ImGuiWindow *window, int layer)
Definition: imgui.cpp:5815
static void DockNodeTreeUpdateSplitterFindTouchingNode(ImGuiDockNode *node, ImGuiAxis axis, int side, ImVector< ImGuiDockNode * > *touching_nodes)
Definition: imgui.cpp:19733
int ImStrlenW(const ImWchar *str)
Definition: imgui.cpp:2158
const char * ImStrchrRange(const char *str, const char *str_end, char c)
Definition: imgui.cpp:2152
static void CalcWindowContentSizes(ImGuiWindow *window, ImVec2 *content_size_current, ImVec2 *content_size_ideal)
Definition: imgui.cpp:6833
static const ImVec2 TOOLTIP_DEFAULT_PIVOT_TOUCH
Definition: imgui.cpp:1257
static void ImGuiListClipper_SortAndFuseRanges(ImVector< ImGuiListClipperRange > &ranges, int offset=0)
Definition: imgui.cpp:3144
static IM_MSVC_RUNTIME_CHECKS_OFF int IMGUI_CDECL PairComparerByID(const void *lhs, const void *rhs)
Definition: imgui.cpp:2839
int ImFormatString(char *buf, size_t buf_size, const char *fmt,...)
Definition: imgui.cpp:2250
static bool GetSkipItemForListClipping()
Definition: imgui.cpp:3138
ImVec2 ImLineClosestPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &p)
Definition: imgui.cpp:2049
static const char *const GKeyNames[]
Definition: imgui.cpp:9766
static bool IsDockNodeTitleBarHighlighted(ImGuiDockNode *node, ImGuiDockNode *root_node)
Definition: imgui.cpp:18838
static void FreeWrapper(void *ptr, void *user_data)
Definition: imgui.cpp:1396
static ImGuiCol GetWindowBgColorIdx(ImGuiWindow *window)
Definition: imgui.cpp:6915
static const char * FormatTextureIDForDebugDisplay(char *buf, int buf_size, ImTextureID tex_id)
Definition: imgui.cpp:21509
void ImStrTrimBlanks(char *buf)
Definition: imgui.cpp:2204
void ImFormatStringToTempBufferV(const char **out_buf, const char **out_buf_end, const char *fmt, va_list args)
Definition: imgui.cpp:2296
static const ImGuiResizeBorderDef resize_border_def[4]
Definition: imgui.cpp:6960
static void ShowDebugLogFlag(const char *name, ImGuiDebugLogFlags flags)
Definition: imgui.cpp:23183
IM_MSVC_RUNTIME_CHECKS_RESTORE IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b)
Definition: imgui.cpp:2732
static void DebugPrintInputEvent(const char *prefix, const ImGuiInputEvent *e)
Definition: imgui.cpp:10763
static ImDrawList * GetViewportBgFgDrawList(ImGuiViewportP *viewport, size_t drawlist_no, const char *drawlist_name)
Definition: imgui.cpp:5118
static void DockSettingsHandler_DockNodeToSettings(ImGuiDockContext *dc, ImGuiDockNode *node, int depth)
Definition: imgui.cpp:20965
static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER
Definition: imgui.cpp:1252
static void WindowSettingsHandler_ReadLine(ImGuiContext *, ImGuiSettingsHandler *, void *entry, const char *line)
Definition: imgui.cpp:15982
const char * ImStrSkipBlank(const char *str)
Definition: imgui.cpp:2219
static const ImVec2 TOOLTIP_DEFAULT_OFFSET_TOUCH
Definition: imgui.cpp:1256
static const float FONT_DEFAULT_SIZE
Definition: imgui.cpp:1245
static void WindowSettingsHandler_ClearAll(ImGuiContext *, ImGuiSettingsHandler *)
Definition: imgui.cpp:15961
const char * ImTextCharToUtf8(char out_buf[5], unsigned int c)
Definition: imgui.cpp:2647
static void * WindowSettingsHandler_ReadOpen(ImGuiContext *, ImGuiSettingsHandler *, const char *name)
Definition: imgui.cpp:15969
static int IMGUI_CDECL TabItemComparerByDockOrder(const void *lhs, const void *rhs)
Definition: imgui.cpp:18759
static const ImU32 DEBUG_LOCATE_ITEM_COLOR
Definition: imgui.cpp:23337
static ImGuiHoveredFlags ApplyHoverFlagsForTooltip(ImGuiHoveredFlags user_flags, ImGuiHoveredFlags shared_flags)
Definition: imgui.cpp:4749
static void SetWindowConditionAllowFlags(ImGuiWindow *window, ImGuiCond flags, bool enabled)
Definition: imgui.cpp:6677
static ImGuiWindow * GetWindowForTitleDisplay(ImGuiWindow *window)
Definition: imgui.cpp:6770
static void SetWindowActiveForSkipRefresh(ImGuiWindow *window)
Definition: imgui.cpp:7568
static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext *ctx, const char *text)
Definition: imgui.cpp:21187
static void LockWheelingWindow(ImGuiWindow *window, float wheel_amount)
Definition: imgui.cpp:10591
static void MetricsHelpMarker(const char *desc)
Definition: imgui.cpp:21529
static void AddRootWindowToDrawData(ImGuiWindow *window)
Definition: imgui.cpp:5835
static void TranslateWindow(ImGuiWindow *window, const ImVec2 &delta)
Definition: imgui.cpp:5333
bool ImTriangleContainsPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
Definition: imgui.cpp:2062
static void DockNodeFindInfo(ImGuiDockNode *node, ImGuiDockNodeTreeInfo *info)
Definition: imgui.cpp:18251
static void DockNodeSetupHostWindow(ImGuiDockNode *node, ImGuiWindow *host_window)
Definition: imgui.cpp:18434
ImU64 ImFileWrite(const void *data, ImU64 sz, ImU64 count, ImFileHandle f)
Definition: imgui.cpp:2477
static const float NAV_ACTIVATE_HIGHLIGHT_TIMER
Definition: imgui.cpp:1250
#define IMGUI_DEBUG_NAV_SCORING
Definition: imgui.cpp:1241
int ImTextCountUtf8BytesFromStr(const ImWchar *in_text, const ImWchar *in_text_end)
Definition: imgui.cpp:2686
static void * MallocWrapper(size_t size, void *user_data)
Definition: imgui.cpp:1395
static void SetupDrawListSharedData()
Definition: imgui.cpp:5487
static int IMGUI_CDECL ViewportComparerByLastFocusedStampCount(const void *lhs, const void *rhs)
Definition: imgui.cpp:21385
ImU64 ImFileRead(void *data, ImU64 sz, ImU64 count, ImFileHandle f)
Definition: imgui.cpp:2476
ImGuiID ImHashStr(const char *data_p, size_t data_size, ImGuiID seed)
Definition: imgui.cpp:2404
static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER
Definition: imgui.cpp:1251
static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext *ctx, const char *path)
Definition: imgui.cpp:21230
static const ImGuiLocEntry GLocalizationEntriesEnUS[]
Definition: imgui.cpp:4054
static void CalcResizePosSizeFromAnyCorner(ImGuiWindow *window, const ImVec2 &corner_target, const ImVec2 &corner_norm, ImVec2 *out_pos, ImVec2 *out_size)
Definition: imgui.cpp:6924
const char * ImTextFindPreviousUtf8Codepoint(const char *in_text_start, const char *in_text_curr)
Definition: imgui.cpp:2700
static ImGuiMemAllocFunc GImAllocatorAllocFunc
Definition: imgui.cpp:1401
static int CalcRoutingScore(ImGuiID focus_scope_id, ImGuiID owner_id, ImGuiInputFlags flags)
Definition: imgui.cpp:9971
IM_MSVC_RUNTIME_CHECKS_OFF int ImTextCharFromUtf8(unsigned int *out_char, const char *in_text, const char *in_text_end)
Definition: imgui.cpp:2531
static ImGuiInputEvent * FindLatestInputEvent(ImGuiContext *ctx, ImGuiInputEventType type, int arg=-1)
Definition: imgui.cpp:1736
int ImTextCountCharsFromUtf8(const char *in_text, const char *in_text_end)
Definition: imgui.cpp:2599
ImGuiDockRequestType
Definition: imgui.cpp:17185
@ ImGuiDockRequestType_Split
Definition: imgui.cpp:17189
@ ImGuiDockRequestType_Dock
Definition: imgui.cpp:17187
@ ImGuiDockRequestType_None
Definition: imgui.cpp:17186
@ ImGuiDockRequestType_Undock
Definition: imgui.cpp:17188
bool ImFileClose(ImFileHandle f)
Definition: imgui.cpp:2474
static const float NAV_WINDOWING_LIST_APPEAR_DELAY
Definition: imgui.cpp:1249
static void SameLineOrWrap(const ImVec2 &size)
Definition: imgui.cpp:23174
static ImVec2 CalcWindowAutoFitSize(ImGuiWindow *window, const ImVec2 &size_contents)
Definition: imgui.cpp:6853
void * ImFileLoadToMemory(const char *filename, const char *mode, size_t *out_file_size, int padding_bytes)
Definition: imgui.cpp:2483
static void ImBezierCubicClosestPointCasteljauStep(const ImVec2 &p, ImVec2 &p_closest, ImVec2 &p_last, float &p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
Definition: imgui.cpp:2004
static void RenderViewportsThumbnails()
Definition: imgui.cpp:21357
const char * ImStristr(const char *haystack, const char *haystack_end, const char *needle, const char *needle_end)
Definition: imgui.cpp:2181
static const char * GetFallbackWindowNameForWindowingList(ImGuiWindow *window)
Definition: imgui.cpp:15040
ImVec2 ImBezierCubicClosestPoint(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, const ImVec2 &p4, const ImVec2 &p, int num_segments)
Definition: imgui.cpp:1981
static ImGuiID GetRoutingIdFromOwnerId(ImGuiID owner_id)
Definition: imgui.cpp:9921
ImGuiID ImHashData(const void *data_p, size_t data_size, ImGuiID seed)
Definition: imgui.cpp:2376
ImU64 ImFileGetSize(ImFileHandle f)
Definition: imgui.cpp:2475
int ImStricmp(const char *str1, const char *str2)
Definition: imgui.cpp:2102
int ImTextCountUtf8BytesFromChar(const char *in_text, const char *in_text_end)
Definition: imgui.cpp:2655
static ImVec2 CalcWindowMinSize(ImGuiWindow *window)
Definition: imgui.cpp:6780
ImFileHandle ImFileOpen(const char *filename, const char *mode)
Definition: imgui.cpp:2449
static void DebugFlashStyleColorStop()
Definition: imgui.cpp:21480
static void RenderWindowOuterSingleBorder(ImGuiWindow *window, int border_n, ImU32 border_col, float border_size)
Definition: imgui.cpp:7240
int ImTextStrFromUtf8(ImWchar *buf, int buf_size, const char *in_text, const char *in_text_end, const char **in_text_remaining)
Definition: imgui.cpp:2583
void ImStrncpy(char *dst, const char *src, size_t count)
Definition: imgui.cpp:2116
static void AddWindowToSortBuffer(ImVector< ImGuiWindow * > *out_sorted_windows, ImGuiWindow *window)
Definition: imgui.cpp:5799
static void StoreDockStyleForWindow(ImGuiWindow *window)
Definition: imgui.cpp:20593
static IM_MSVC_RUNTIME_CHECKS_RESTORE ImGuiKeyChord GetModForLRModKey(ImGuiKey key)
Definition: imgui.cpp:9731
ImVec2 ImTriangleClosestPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
Definition: imgui.cpp:2081
static const ImU32 GCrc32LookupTable[256]
Definition: imgui.cpp:2331
int ImTextCountLines(const char *in_text, const char *in_text_end)
Definition: imgui.cpp:2711
static ImVec2 FixLargeWindowsWhenUndocking(const ImVec2 &size, ImGuiViewport *ref_viewport)
Definition: imgui.cpp:17866
ImGuiDir
Definition: imgui.h:1552
@ ImGuiDir_Down
Definition: imgui.h:1557
@ ImGuiDir_Right
Definition: imgui.h:1555
@ ImGuiDir_COUNT
Definition: imgui.h:1558
@ ImGuiDir_Up
Definition: imgui.h:1556
@ ImGuiDir_None
Definition: imgui.h:1553
@ ImGuiDir_Left
Definition: imgui.h:1554
unsigned short ImWchar16
Definition: imgui.h:270
@ ImGuiFocusedFlags_AnyWindow
Definition: imgui.h:1437
@ ImGuiFocusedFlags_DockHierarchy
Definition: imgui.h:1439
@ ImGuiFocusedFlags_NoPopupHierarchy
Definition: imgui.h:1438
int ImGuiTreeNodeFlags
Definition: imgui.h:263
int ImFontAtlasRectId
Definition: imgui.h:3658
int ImGuiViewportFlags
Definition: imgui.h:264
int ImGuiKeyChord
Definition: imgui.h:253
#define IM_COL32_WHITE
Definition: imgui.h:3002
@ ImGuiDragDropFlags_AcceptBeforeDelivery
Definition: imgui.h:1518
@ ImGuiDragDropFlags_PayloadNoCrossContext
Definition: imgui.h:1515
@ ImGuiDragDropFlags_SourceNoPreviewTooltip
Definition: imgui.h:1509
@ ImGuiDragDropFlags_PayloadNoCrossProcess
Definition: imgui.h:1516
@ ImGuiDragDropFlags_SourceAllowNullID
Definition: imgui.h:1512
@ ImGuiDragDropFlags_None
Definition: imgui.h:1507
@ ImGuiDragDropFlags_SourceExtern
Definition: imgui.h:1513
@ ImGuiDragDropFlags_AcceptNoDrawDefaultRect
Definition: imgui.h:1519
@ ImGuiDragDropFlags_SourceNoDisableHover
Definition: imgui.h:1510
@ ImGuiDragDropFlags_PayloadAutoExpire
Definition: imgui.h:1514
@ ImGuiDragDropFlags_SourceNoHoldToOpenOthers
Definition: imgui.h:1511
@ ImGuiDragDropFlags_AcceptNoPreviewTooltip
Definition: imgui.h:1520
int ImGuiWindowFlags
Definition: imgui.h:265
@ ImGuiDataType_Float
Definition: imgui.h:1543
@ ImGuiDataType_String
Definition: imgui.h:1546
@ ImGuiDataType_S32
Definition: imgui.h:1539
unsigned int ImU32
Definition: imgui.h:162
#define IM_COL32(R, G, B, A)
Definition: imgui.h:3001
@ ImGuiHoveredFlags_DelayShort
Definition: imgui.h:1478
@ ImGuiHoveredFlags_None
Definition: imgui.h:1448
@ ImGuiHoveredFlags_DelayNone
Definition: imgui.h:1477
@ ImGuiHoveredFlags_ForTooltip
Definition: imgui.h:1471
@ ImGuiHoveredFlags_AllowWhenBlockedByActiveItem
Definition: imgui.h:1456
@ ImGuiHoveredFlags_AllowWhenBlockedByPopup
Definition: imgui.h:1454
@ ImGuiHoveredFlags_NoNavOverride
Definition: imgui.h:1460
@ ImGuiHoveredFlags_AllowWhenOverlappedByItem
Definition: imgui.h:1457
@ ImGuiHoveredFlags_Stationary
Definition: imgui.h:1476
@ ImGuiHoveredFlags_NoPopupHierarchy
Definition: imgui.h:1452
@ ImGuiHoveredFlags_NoSharedDelay
Definition: imgui.h:1480
@ ImGuiHoveredFlags_ChildWindows
Definition: imgui.h:1449
@ ImGuiHoveredFlags_RootWindow
Definition: imgui.h:1450
@ ImGuiHoveredFlags_AnyWindow
Definition: imgui.h:1451
@ ImGuiHoveredFlags_AllowWhenDisabled
Definition: imgui.h:1459
@ ImGuiHoveredFlags_DockHierarchy
Definition: imgui.h:1453
@ ImGuiHoveredFlags_DelayNormal
Definition: imgui.h:1479
@ ImGuiHoveredFlags_AllowWhenOverlappedByWindow
Definition: imgui.h:1458
unsigned int ImGuiID
Definition: imgui.h:156
#define IM_COL32_G_SHIFT
Definition: imgui.h:2995
@ ImGuiConfigFlags_NoMouse
Definition: imgui.h:1732
@ ImGuiConfigFlags_DpiEnableScaleFonts
Definition: imgui.h:1750
@ ImGuiConfigFlags_NavEnableSetMousePos
Definition: imgui.h:1748
@ ImGuiConfigFlags_NoKeyboard
Definition: imgui.h:1734
@ ImGuiConfigFlags_NavEnableGamepad
Definition: imgui.h:1731
@ ImGuiConfigFlags_ViewportsEnable
Definition: imgui.h:1741
@ ImGuiConfigFlags_DockingEnable
Definition: imgui.h:1737
@ ImGuiConfigFlags_None
Definition: imgui.h:1729
@ ImGuiConfigFlags_NavEnableKeyboard
Definition: imgui.h:1730
@ ImGuiConfigFlags_NavNoCaptureKeyboard
Definition: imgui.h:1749
@ ImGuiConfigFlags_DpiEnableScaleViewports
Definition: imgui.h:1751
void *(* ImGuiMemAllocFunc)(size_t sz, void *user_data)
Definition: imgui.h:285
int ImDrawListFlags
Definition: imgui.h:237
int ImGuiCol
Definition: imgui.h:223
void(* ImGuiSizeCallback)(ImGuiSizeCallbackData *data)
Definition: imgui.h:284
IM_MSVC_RUNTIME_CHECKS_RESTORE typedef ImU64 ImTextureID
Definition: imgui.h:337
ImWchar16 ImWchar
Definition: imgui.h:274
#define IM_COL32_R_SHIFT
Definition: imgui.h:2994
@ ImDrawListFlags_None
Definition: imgui.h:3305
@ ImDrawListFlags_AntiAliasedLinesUseTex
Definition: imgui.h:3307
@ ImDrawListFlags_AntiAliasedFill
Definition: imgui.h:3308
@ ImDrawListFlags_AntiAliasedLines
Definition: imgui.h:3306
@ ImDrawListFlags_AllowVtxOffset
Definition: imgui.h:3309
#define IM_UNUSED(_VAR)
Definition: imgui.h:99
@ ImGuiBackendFlags_RendererHasTextures
Definition: imgui.h:1763
@ ImGuiBackendFlags_HasGamepad
Definition: imgui.h:1759
@ ImGuiBackendFlags_HasMouseHoveredViewport
Definition: imgui.h:1767
@ ImGuiBackendFlags_RendererHasViewports
Definition: imgui.h:1768
@ ImGuiBackendFlags_HasSetMousePos
Definition: imgui.h:1761
@ ImGuiBackendFlags_PlatformHasViewports
Definition: imgui.h:1766
@ ImGuiBackendFlags_RendererHasVtxOffset
Definition: imgui.h:1762
@ ImGuiBackendFlags_None
Definition: imgui.h:1758
@ ImGuiMouseCursor_None
Definition: imgui.h:1991
@ ImGuiMouseCursor_ResizeNWSE
Definition: imgui.h:1998
@ ImGuiMouseCursor_Hand
Definition: imgui.h:1999
@ ImGuiMouseCursor_Progress
Definition: imgui.h:2001
@ ImGuiMouseCursor_ResizeEW
Definition: imgui.h:1996
@ ImGuiMouseCursor_COUNT
Definition: imgui.h:2003
@ ImGuiMouseCursor_ResizeNS
Definition: imgui.h:1995
@ ImGuiMouseCursor_ResizeNESW
Definition: imgui.h:1997
@ ImGuiMouseCursor_Wait
Definition: imgui.h:2000
@ ImGuiMouseCursor_Arrow
Definition: imgui.h:1992
@ ImGuiChildFlags_AlwaysAutoResize
Definition: imgui.h:1239
@ ImGuiChildFlags_AlwaysUseWindowPadding
Definition: imgui.h:1234
@ ImGuiChildFlags_AutoResizeY
Definition: imgui.h:1238
@ ImGuiChildFlags_FrameStyle
Definition: imgui.h:1240
@ ImGuiChildFlags_ResizeY
Definition: imgui.h:1236
@ ImGuiChildFlags_AutoResizeX
Definition: imgui.h:1237
@ ImGuiChildFlags_ResizeX
Definition: imgui.h:1235
@ ImGuiChildFlags_NavFlattened
Definition: imgui.h:1241
@ ImGuiChildFlags_Borders
Definition: imgui.h:1233
unsigned char ImU8
Definition: imgui.h:158
int ImGuiHoveredFlags
Definition: imgui.h:249
ImGuiMouseSource
Definition: imgui.h:2011
@ ImGuiMouseSource_TouchScreen
Definition: imgui.h:2013
@ ImGuiMouseSource_COUNT
Definition: imgui.h:2015
@ ImGuiMouseSource_Mouse
Definition: imgui.h:2012
void IM_DELETE(T *p)
Definition: imgui.h:2221
#define IM_ALLOC(_SIZE)
Definition: imgui.h:2217
#define IM_PLACEMENT_NEW(_PTR)
Definition: imgui.h:2219
#define IMGUI_API
Definition: imgui.h:87
int ImGuiFocusedFlags
Definition: imgui.h:248
@ ImGuiTableColumnFlags_WidthFixed
Definition: imgui.h:2117
@ ImGuiTableColumnFlags_WidthStretch
Definition: imgui.h:2116
@ ImFontFlags_None
Definition: imgui.h:3886
int ImGuiDataType
Definition: imgui.h:225
int ImGuiDragDropFlags
Definition: imgui.h:247
@ ImGuiPopupFlags_MouseButtonMask_
Definition: imgui.h:1356
@ ImGuiPopupFlags_AnyPopupLevel
Definition: imgui.h:1363
@ ImGuiPopupFlags_NoOpenOverExistingPopup
Definition: imgui.h:1360
@ ImGuiPopupFlags_AnyPopupId
Definition: imgui.h:1362
@ ImGuiPopupFlags_NoOpenOverItems
Definition: imgui.h:1361
@ ImGuiPopupFlags_NoReopen
Definition: imgui.h:1358
@ ImGuiPopupFlags_None
Definition: imgui.h:1352
@ ImGuiTabBarFlags_NoCloseWithMiddleMouseButton
Definition: imgui.h:1406
@ ImGuiTabBarFlags_DrawSelectedOverline
Definition: imgui.h:1409
@ ImGuiTabBarFlags_AutoSelectNewTabs
Definition: imgui.h:1404
@ ImGuiTabBarFlags_Reorderable
Definition: imgui.h:1403
@ ImGuiTabItemFlags_None
Definition: imgui.h:1419
@ ImGuiTabItemFlags_UnsavedDocument
Definition: imgui.h:1420
@ ImGuiTabItemFlags_NoCloseWithMiddleMouseButton
Definition: imgui.h:1422
#define IM_NEW(_TYPE)
Definition: imgui.h:2220
int ImGuiTabBarFlags
Definition: imgui.h:258
@ ImGuiItemFlags_AllowDuplicateId
Definition: imgui.h:1259
@ ImGuiItemFlags_NoTabStop
Definition: imgui.h:1254
@ ImGuiItemFlags_None
Definition: imgui.h:1253
@ ImGuiItemFlags_NoNavDefaultFocus
Definition: imgui.h:1256
@ ImGuiItemFlags_AutoClosePopups
Definition: imgui.h:1258
@ ImGuiItemFlags_NoNav
Definition: imgui.h:1255
@ ImGuiStyleVar_ImageBorderSize
Definition: imgui.h:1877
@ ImGuiStyleVar_ChildRounding
Definition: imgui.h:1862
@ ImGuiStyleVar_WindowRounding
Definition: imgui.h:1858
@ ImGuiStyleVar_FramePadding
Definition: imgui.h:1866
@ ImGuiStyleVar_WindowPadding
Definition: imgui.h:1857
@ ImGuiStyleVar_ChildBorderSize
Definition: imgui.h:1863
@ ImGuiStyleVar_WindowBorderSize
Definition: imgui.h:1859
@ ImGuiStyleVar_COUNT
Definition: imgui.h:1892
unsigned long long ImU64
Definition: imgui.h:164
@ ImGuiInputTextFlags_ReadOnly
Definition: imgui.h:1281
#define IM_COL32_B_SHIFT
Definition: imgui.h:2996
@ ImGuiTableBgTarget_CellBg
Definition: imgui.h:2167
unsigned short ImU16
Definition: imgui.h:160
#define IM_MSVC_RUNTIME_CHECKS_OFF
Definition: imgui.h:123
@ ImFontAtlasFlags_NoBakedLines
Definition: imgui.h:3679
@ ImGuiInputFlags_None
Definition: imgui.h:1706
@ ImGuiInputFlags_RouteOverActive
Definition: imgui.h:1718
@ ImGuiInputFlags_RouteFromRootWindow
Definition: imgui.h:1720
@ ImGuiInputFlags_RouteOverFocused
Definition: imgui.h:1717
@ ImGuiInputFlags_RouteActive
Definition: imgui.h:1712
@ ImGuiInputFlags_RouteGlobal
Definition: imgui.h:1714
@ ImGuiInputFlags_RouteFocused
Definition: imgui.h:1713
@ ImGuiInputFlags_Tooltip
Definition: imgui.h:1723
@ ImGuiInputFlags_Repeat
Definition: imgui.h:1707
@ ImGuiInputFlags_RouteAlways
Definition: imgui.h:1715
@ ImGuiInputFlags_RouteUnlessBgFocused
Definition: imgui.h:1719
#define IM_COL32_A_MASK
Definition: imgui.h:2998
@ ImGuiCol_TextLink
Definition: imgui.h:1826
@ ImGuiCol_BorderShadow
Definition: imgui.h:1780
@ ImGuiCol_TextDisabled
Definition: imgui.h:1775
@ ImGuiCol_FrameBgHovered
Definition: imgui.h:1782
@ ImGuiCol_HeaderActive
Definition: imgui.h:1800
@ ImGuiCol_TitleBgCollapsed
Definition: imgui.h:1786
@ ImGuiCol_PlotHistogramHovered
Definition: imgui.h:1820
@ ImGuiCol_ScrollbarGrab
Definition: imgui.h:1789
@ ImGuiCol_TextSelectedBg
Definition: imgui.h:1827
@ ImGuiCol_MenuBarBg
Definition: imgui.h:1787
@ ImGuiCol_PlotHistogram
Definition: imgui.h:1819
@ ImGuiCol_Header
Definition: imgui.h:1798
@ ImGuiCol_TabHovered
Definition: imgui.h:1808
@ ImGuiCol_HeaderHovered
Definition: imgui.h:1799
@ ImGuiCol_FrameBg
Definition: imgui.h:1781
@ ImGuiCol_DockingPreview
Definition: imgui.h:1815
@ ImGuiCol_ModalWindowDimBg
Definition: imgui.h:1833
@ ImGuiCol_TabSelectedOverline
Definition: imgui.h:1811
@ ImGuiCol_DragDropTarget
Definition: imgui.h:1829
@ ImGuiCol_Button
Definition: imgui.h:1795
@ ImGuiCol_ButtonHovered
Definition: imgui.h:1796
@ ImGuiCol_ButtonActive
Definition: imgui.h:1797
@ ImGuiCol_SeparatorActive
Definition: imgui.h:1803
@ ImGuiCol_TableRowBg
Definition: imgui.h:1824
@ ImGuiCol_TreeLines
Definition: imgui.h:1828
@ ImGuiCol_Border
Definition: imgui.h:1779
@ ImGuiCol_FrameBgActive
Definition: imgui.h:1783
@ ImGuiCol_ScrollbarGrabActive
Definition: imgui.h:1791
@ ImGuiCol_WindowBg
Definition: imgui.h:1776
@ ImGuiCol_TableHeaderBg
Definition: imgui.h:1821
@ ImGuiCol_TabDimmedSelectedOverline
Definition: imgui.h:1814
@ ImGuiCol_TitleBgActive
Definition: imgui.h:1785
@ ImGuiCol_Text
Definition: imgui.h:1774
@ ImGuiCol_ResizeGripActive
Definition: imgui.h:1806
@ ImGuiCol_NavCursor
Definition: imgui.h:1830
@ ImGuiCol_TabDimmed
Definition: imgui.h:1812
@ ImGuiCol_TableRowBgAlt
Definition: imgui.h:1825
@ ImGuiCol_ChildBg
Definition: imgui.h:1777
@ ImGuiCol_PopupBg
Definition: imgui.h:1778
@ ImGuiCol_Tab
Definition: imgui.h:1809
@ ImGuiCol_ScrollbarBg
Definition: imgui.h:1788
@ ImGuiCol_InputTextCursor
Definition: imgui.h:1807
@ ImGuiCol_CheckMark
Definition: imgui.h:1792
@ ImGuiCol_TabSelected
Definition: imgui.h:1810
@ ImGuiCol_TableBorderLight
Definition: imgui.h:1823
@ ImGuiCol_ScrollbarGrabHovered
Definition: imgui.h:1790
@ ImGuiCol_COUNT
Definition: imgui.h:1834
@ ImGuiCol_TitleBg
Definition: imgui.h:1784
@ ImGuiCol_PlotLines
Definition: imgui.h:1817
@ ImGuiCol_ResizeGripHovered
Definition: imgui.h:1805
@ ImGuiCol_NavWindowingHighlight
Definition: imgui.h:1831
@ ImGuiCol_TableBorderStrong
Definition: imgui.h:1822
@ ImGuiCol_DockingEmptyBg
Definition: imgui.h:1816
@ ImGuiCol_SliderGrabActive
Definition: imgui.h:1794
@ ImGuiCol_SliderGrab
Definition: imgui.h:1793
@ ImGuiCol_SeparatorHovered
Definition: imgui.h:1802
@ ImGuiCol_ResizeGrip
Definition: imgui.h:1804
@ ImGuiCol_Separator
Definition: imgui.h:1801
@ ImGuiCol_TabDimmedSelected
Definition: imgui.h:1813
@ ImGuiCol_NavWindowingDimBg
Definition: imgui.h:1832
@ ImGuiCol_PlotLinesHovered
Definition: imgui.h:1818
int ImGuiMouseCursor
Definition: imgui.h:227
#define IM_UNICODE_CODEPOINT_INVALID
Definition: imgui.h:2771
int ImGuiChildFlags
Definition: imgui.h:242
ImGuiKey
Definition: imgui.h:1576
@ ImGuiKey_GamepadFaceRight
Definition: imgui.h:1643
@ ImGuiKey_PageUp
Definition: imgui.h:1586
@ ImGuiMod_Mask_
Definition: imgui.h:1691
@ ImGuiKey_S
Definition: imgui.h:1601
@ ImGuiKey_RightArrow
Definition: imgui.h:1583
@ ImGuiKey_RightSuper
Definition: imgui.h:1597
@ ImGuiKey_Escape
Definition: imgui.h:1595
@ ImGuiKey_W
Definition: imgui.h:1602
@ ImGuiKey_LeftShift
Definition: imgui.h:1596
@ ImGuiKey_KeypadMultiply
Definition: imgui.h:1627
@ ImGuiKey_GamepadLStickDown
Definition: imgui.h:1659
@ ImGuiKey_Keypad9
Definition: imgui.h:1624
@ ImGuiKey_DownArrow
Definition: imgui.h:1585
@ ImGuiKey_GamepadFaceUp
Definition: imgui.h:1644
@ ImGuiKey_RightShift
Definition: imgui.h:1597
@ ImGuiKey_LeftSuper
Definition: imgui.h:1596
@ ImGuiKey_0
Definition: imgui.h:1599
@ ImGuiKey_Home
Definition: imgui.h:1588
@ ImGuiKey_ReservedForModCtrl
Definition: imgui.h:1670
@ ImGuiKey_NamedKey_BEGIN
Definition: imgui.h:1579
@ ImGuiKey_Equal
Definition: imgui.h:1613
@ ImGuiKey_Z
Definition: imgui.h:1602
@ ImGuiKey_RightCtrl
Definition: imgui.h:1597
@ ImGuiMod_Shift
Definition: imgui.h:1688
@ ImGuiMod_Alt
Definition: imgui.h:1689
@ ImGuiMod_Ctrl
Definition: imgui.h:1687
@ ImGuiKey_GamepadDpadDown
Definition: imgui.h:1649
@ ImGuiKey_KeypadAdd
Definition: imgui.h:1629
@ ImGuiKey_None
Definition: imgui.h:1578
@ ImGuiKey_Pause
Definition: imgui.h:1622
@ ImGuiKey_ReservedForModAlt
Definition: imgui.h:1670
@ ImGuiKey_MouseWheelX
Definition: imgui.h:1667
@ ImGuiKey_GraveAccent
Definition: imgui.h:1617
@ ImGuiKey_Tab
Definition: imgui.h:1581
@ ImGuiKey_GamepadR1
Definition: imgui.h:1651
@ ImGuiMod_Super
Definition: imgui.h:1690
@ ImGuiKey_ReservedForModShift
Definition: imgui.h:1670
@ ImGuiKey_A
Definition: imgui.h:1600
@ ImGuiKey_C
Definition: imgui.h:1600
@ ImGuiKey_PageDown
Definition: imgui.h:1587
@ ImGuiKey_KeypadDecimal
Definition: imgui.h:1625
@ ImGuiKey_F
Definition: imgui.h:1600
@ ImGuiKey_R
Definition: imgui.h:1601
@ ImGuiKey_Comma
Definition: imgui.h:1608
@ ImGuiKey_Slash
Definition: imgui.h:1611
@ ImGuiKey_KeypadSubtract
Definition: imgui.h:1628
@ ImGuiMod_None
Definition: imgui.h:1686
@ ImGuiKey_Keypad0
Definition: imgui.h:1623
@ ImGuiKey_X
Definition: imgui.h:1602
@ ImGuiKey_NamedKey_END
Definition: imgui.h:1673
@ ImGuiKey_GamepadL1
Definition: imgui.h:1650
@ ImGuiKey_RightBracket
Definition: imgui.h:1616
@ ImGuiKey_GamepadLStickUp
Definition: imgui.h:1658
@ ImGuiKey_Minus
Definition: imgui.h:1609
@ ImGuiKey_KeypadEqual
Definition: imgui.h:1631
@ ImGuiKey_GamepadFaceDown
Definition: imgui.h:1645
@ ImGuiKey_Semicolon
Definition: imgui.h:1612
@ ImGuiKey_E
Definition: imgui.h:1600
@ ImGuiKey_UpArrow
Definition: imgui.h:1584
@ ImGuiKey_GamepadLStickLeft
Definition: imgui.h:1656
@ ImGuiKey_MouseLeft
Definition: imgui.h:1667
@ ImGuiKey_Period
Definition: imgui.h:1610
@ ImGuiKey_Apostrophe
Definition: imgui.h:1607
@ ImGuiKey_Space
Definition: imgui.h:1593
@ ImGuiKey_ReservedForModSuper
Definition: imgui.h:1670
@ ImGuiKey_9
Definition: imgui.h:1599
@ ImGuiKey_LeftArrow
Definition: imgui.h:1582
@ ImGuiKey_RightAlt
Definition: imgui.h:1597
@ ImGuiKey_Q
Definition: imgui.h:1601
@ ImGuiKey_MouseWheelY
Definition: imgui.h:1667
@ ImGuiKey_End
Definition: imgui.h:1589
@ ImGuiKey_GamepadDpadUp
Definition: imgui.h:1648
@ ImGuiKey_GamepadDpadRight
Definition: imgui.h:1647
@ ImGuiKey_GamepadDpadLeft
Definition: imgui.h:1646
@ ImGuiKey_NamedKey_COUNT
Definition: imgui.h:1674
@ ImGuiKey_CapsLock
Definition: imgui.h:1618
@ ImGuiKey_V
Definition: imgui.h:1602
@ ImGuiKey_Enter
Definition: imgui.h:1594
@ ImGuiKey_GamepadFaceLeft
Definition: imgui.h:1642
@ ImGuiKey_D
Definition: imgui.h:1600
@ ImGuiKey_KeypadDivide
Definition: imgui.h:1626
@ ImGuiKey_LeftCtrl
Definition: imgui.h:1596
@ ImGuiKey_LeftBracket
Definition: imgui.h:1614
@ ImGuiKey_LeftAlt
Definition: imgui.h:1596
@ ImGuiKey_GamepadLStickRight
Definition: imgui.h:1657
@ ImGuiKey_KeypadEnter
Definition: imgui.h:1630
int ImGuiInputFlags
Definition: imgui.h:250
@ ImGuiMouseButton_COUNT
Definition: imgui.h:1984
@ ImGuiMouseButton_Left
Definition: imgui.h:1981
@ ImGuiDockNodeFlags_None
Definition: imgui.h:1488
@ ImGuiDockNodeFlags_AutoHideTabBar
Definition: imgui.h:1495
@ ImGuiDockNodeFlags_KeepAliveOnly
Definition: imgui.h:1489
@ ImGuiDockNodeFlags_NoDockingOverCentralNode
Definition: imgui.h:1491
@ ImGuiDockNodeFlags_PassthruCentralNode
Definition: imgui.h:1492
@ ImGuiDockNodeFlags_NoDockingInCentralNode
Definition: imgui.h:1500
@ ImGuiDockNodeFlags_NoResize
Definition: imgui.h:1494
@ ImGuiDockNodeFlags_NoUndocking
Definition: imgui.h:1496
@ ImGuiDockNodeFlags_NoDockingSplit
Definition: imgui.h:1493
#define IMGUI_VERSION
Definition: imgui.h:31
@ ImGuiTreeNodeFlags_Selected
Definition: imgui.h:1309
@ ImGuiTreeNodeFlags_DrawLinesToNodes
Definition: imgui.h:1333
@ ImGuiTreeNodeFlags_None
Definition: imgui.h:1308
@ ImGuiTreeNodeFlags_DrawLinesFull
Definition: imgui.h:1332
@ ImGuiTreeNodeFlags_DrawLinesNone
Definition: imgui.h:1331
int ImGuiItemFlags
Definition: imgui.h:252
int ImGuiMouseButton
Definition: imgui.h:226
#define IM_FREE(_PTR)
Definition: imgui.h:2218
int ImGuiStyleVar
Definition: imgui.h:228
#define IM_ASSERT(_EXPR)
Definition: imgui.h:96
#define IM_MSVC_RUNTIME_CHECKS_RESTORE
Definition: imgui.h:124
#define ImFontAtlasRectId_Invalid
Definition: imgui.h:3659
@ ImGuiViewportFlags_NoTaskBarIcon
Definition: imgui.h:3974
@ ImGuiViewportFlags_OwnedByApp
Definition: imgui.h:3972
@ ImGuiViewportFlags_NoRendererClear
Definition: imgui.h:3978
@ ImGuiViewportFlags_TopMost
Definition: imgui.h:3980
@ ImGuiViewportFlags_NoDecoration
Definition: imgui.h:3973
@ ImGuiViewportFlags_IsPlatformWindow
Definition: imgui.h:3970
@ ImGuiViewportFlags_IsMinimized
Definition: imgui.h:3984
@ ImGuiViewportFlags_IsPlatformMonitor
Definition: imgui.h:3971
@ ImGuiViewportFlags_NoInputs
Definition: imgui.h:3977
@ ImGuiViewportFlags_CanHostOtherWindows
Definition: imgui.h:3981
@ ImGuiViewportFlags_NoFocusOnAppearing
Definition: imgui.h:3975
@ ImGuiViewportFlags_NoFocusOnClick
Definition: imgui.h:3976
@ ImGuiViewportFlags_IsFocused
Definition: imgui.h:3985
@ ImGuiViewportFlags_None
Definition: imgui.h:3969
@ ImGuiViewportFlags_NoAutoMerge
Definition: imgui.h:3979
@ ImGuiWindowFlags_NoInputs
Definition: imgui.h:1204
@ ImGuiWindowFlags_NoBackground
Definition: imgui.h:1189
@ ImGuiWindowFlags_DockNodeHost
Definition: imgui.h:1207
@ ImGuiWindowFlags_NoNavInputs
Definition: imgui.h:1198
@ ImGuiWindowFlags_AlwaysUseWindowPadding
Definition: imgui.h:1217
@ ImGuiWindowFlags_AlwaysAutoResize
Definition: imgui.h:1188
@ ImGuiWindowFlags_MenuBar
Definition: imgui.h:1192
@ ImGuiWindowFlags_HorizontalScrollbar
Definition: imgui.h:1193
@ ImGuiWindowFlags_Tooltip
Definition: imgui.h:1209
@ ImGuiWindowFlags_NoTitleBar
Definition: imgui.h:1182
@ ImGuiWindowFlags_NoNavFocus
Definition: imgui.h:1199
@ ImGuiWindowFlags_AlwaysVerticalScrollbar
Definition: imgui.h:1196
@ ImGuiWindowFlags_NoFocusOnAppearing
Definition: imgui.h:1194
@ ImGuiWindowFlags_NoCollapse
Definition: imgui.h:1187
@ ImGuiWindowFlags_NoScrollWithMouse
Definition: imgui.h:1186
@ ImGuiWindowFlags_Modal
Definition: imgui.h:1211
@ ImGuiWindowFlags_NoMouseInputs
Definition: imgui.h:1191
@ ImGuiWindowFlags_UnsavedDocument
Definition: imgui.h:1200
@ ImGuiWindowFlags_NoSavedSettings
Definition: imgui.h:1190
@ ImGuiWindowFlags_NoBringToFrontOnFocus
Definition: imgui.h:1195
@ ImGuiWindowFlags_Popup
Definition: imgui.h:1210
@ ImGuiWindowFlags_ChildMenu
Definition: imgui.h:1212
@ ImGuiWindowFlags_AlwaysHorizontalScrollbar
Definition: imgui.h:1197
@ ImGuiWindowFlags_NoDecoration
Definition: imgui.h:1203
@ ImGuiWindowFlags_NavFlattened
Definition: imgui.h:1216
@ ImGuiWindowFlags_NoMove
Definition: imgui.h:1184
@ ImGuiWindowFlags_ChildWindow
Definition: imgui.h:1208
@ ImGuiWindowFlags_NoDocking
Definition: imgui.h:1201
@ ImGuiWindowFlags_NoResize
Definition: imgui.h:1183
@ ImGuiWindowFlags_NoScrollbar
Definition: imgui.h:1185
@ ImGuiWindowFlags_None
Definition: imgui.h:1181
@ ImGuiCond_FirstUseEver
Definition: imgui.h:2026
@ ImGuiCond_Always
Definition: imgui.h:2024
@ ImGuiCond_Once
Definition: imgui.h:2025
@ ImGuiCond_Appearing
Definition: imgui.h:2027
@ ImGuiCond_None
Definition: imgui.h:2023
int ImGuiDockNodeFlags
Definition: imgui.h:246
#define IMGUI_VERSION_NUM
Definition: imgui.h:32
void(* ImGuiMemFreeFunc)(void *ptr, void *user_data)
Definition: imgui.h:286
@ ImGuiTableFlags_Borders
Definition: imgui.h:2076
@ ImGuiTableFlags_RowBg
Definition: imgui.h:2067
@ ImGuiTableFlags_ScrollY
Definition: imgui.h:2097
@ ImGuiTableFlags_SizingFixedFit
Definition: imgui.h:2080
@ ImGuiTableFlags_Resizable
Definition: imgui.h:2060
#define IM_ARRAYSIZE(_ARR)
Definition: imgui.h:98
int ImGuiTabItemFlags
Definition: imgui.h:259
@ ImGuiColorEditFlags_DefaultOptions_
Definition: imgui.h:1944
int ImGuiCond
Definition: imgui.h:224
#define IM_UNICODE_CODEPOINT_MAX
Definition: imgui.h:2775
int ImGuiPopupFlags
Definition: imgui.h:254
int ImDrawFlags
Definition: imgui.h:236
@ ImDrawFlags_None
Definition: imgui.h:3285
@ ImDrawFlags_RoundCornersBottom
Definition: imgui.h:3293
@ ImDrawFlags_Closed
Definition: imgui.h:3286
@ ImDrawFlags_RoundCornersTop
Definition: imgui.h:3292
#define IM_COL32_BLACK
Definition: imgui.h:3003
#define IM_COL32_A_SHIFT
Definition: imgui.h:2997
unsigned short ImDrawIdx
Definition: imgui.h:3189
#define IM_NEWLINE
Definition: imgui_demo.cpp:191
#define IMGUI_CDECL
Definition: imgui_demo.cpp:225
void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas *atlas, ImDrawListSharedData *data)
ImTextureRect * ImFontAtlasPackGetRect(ImFontAtlas *atlas, ImFontAtlasRectId id)
const ImFontLoader * ImFontAtlasGetFontLoaderForStbTruetype()
void ImFontAtlasFontDiscardBakes(ImFontAtlas *atlas, ImFont *font, int unused_frames)
void ImFontAtlasBuildMain(ImFontAtlas *atlas)
void ImFontAtlasBuildGetOversampleFactors(ImFontConfig *src, ImFontBaked *baked, int *out_oversample_h, int *out_oversample_v)
ImVec2 ImBezierCubicCalc(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, const ImVec2 &p4, float t)
bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas *atlas, ImGuiMouseCursor cursor_type, ImVec2 *out_offset, ImVec2 *out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
void ImFontAtlasUpdateNewFrame(ImFontAtlas *atlas, int frame_count, bool renderer_has_textures)
IM_MSVC_RUNTIME_CHECKS_RESTORE void ImFontAtlasDebugLogTextureRequests(ImFontAtlas *atlas)
void ImFontAtlasAddDrawListSharedData(ImFontAtlas *atlas, ImDrawListSharedData *data)
const char * ImTextureDataGetFormatName(ImTextureFormat format)
void ImFontAtlasBuildClear(ImFontAtlas *atlas)
const char * ImTextureDataGetStatusName(ImTextureStatus status)
bool ImFontAtlasFontInitOutput(ImFontAtlas *atlas, ImFont *font)
void ImFontAtlasTextureGrow(ImFontAtlas *atlas, int old_tex_w, int old_tex_h)
void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas *atlas)
void ImFontAtlasFontDestroyOutput(ImFontAtlas *atlas, ImFont *font)
ImGuiContextHookType
@ ImGuiContextHookType_PendingRemoval_
@ ImGuiContextHookType_RenderPost
@ ImGuiContextHookType_NewFramePost
@ ImGuiContextHookType_RenderPre
@ ImGuiContextHookType_EndFramePre
@ ImGuiContextHookType_NewFramePre
@ ImGuiContextHookType_EndFramePost
@ ImGuiContextHookType_Shutdown
static void ImSwap(T &a, T &b)
#define IM_F32_TO_INT8_SAT(_VAL)
#define IMGUI_DEBUG_PRINTF(_FMT,...)
@ ImGuiScrollFlags_KeepVisibleEdgeY
@ ImGuiScrollFlags_MaskX_
@ ImGuiScrollFlags_NoScrollParent
@ ImGuiScrollFlags_AlwaysCenterX
@ ImGuiScrollFlags_KeepVisibleCenterX
@ ImGuiScrollFlags_AlwaysCenterY
@ ImGuiScrollFlags_MaskY_
@ ImGuiScrollFlags_KeepVisibleEdgeX
@ ImGuiScrollFlags_KeepVisibleCenterY
@ ImGuiScrollFlags_None
int ImGuiWindowRefreshFlags
static T ImLerp(T a, T b, float t)
#define ImCos(X)
@ ImGuiItemFlags_Disabled
@ ImGuiItemFlags_NoFocus
@ ImGuiItemFlags_HasSelectionUserData
@ ImGuiItemFlags_NoMarkEdited
@ ImGuiItemFlags_Inputable
@ ImGuiItemFlags_AllowOverlap
@ ImGuiItemFlags_NoNavDisableMouseHover
@ ImGuiItemFlags_NoWindowHoverableCheck
static float ImLengthSqr(const ImVec2 &lhs)
@ ImGuiWindowDockStyleCol_TabSelected
@ ImGuiWindowDockStyleCol_Text
@ ImGuiWindowDockStyleCol_COUNT
#define IMGUI_DEBUG_LOG_DOCKING(...)
static float ImTrunc(float f)
#define ImGuiKey_Mouse_BEGIN
#define ImMemchr
#define ImGuiKey_NavGamepadTweakFast
#define ImGuiKey_Gamepad_END
int ImGuiScrollFlags
@ ImGuiTabBarFlags_SaveSettings
@ ImGuiTabBarFlags_IsFocused
@ ImGuiTabBarFlags_DockNode
static bool ImIsPowerOfTwo(int v)
#define IM_PRIX64
@ ImGuiLocKey_VersionStr
@ ImGuiLocKey_OpenLink_s
@ ImGuiLocKey_DockingDragToUndockOrMoveNode
@ ImGuiLocKey_WindowingMainMenuBar
@ ImGuiLocKey_TableSizeAllDefault
@ ImGuiLocKey_DockingHideTabBar
@ ImGuiLocKey_TableResetOrder
@ ImGuiLocKey_CopyLink
@ ImGuiLocKey_WindowingUntitled
@ ImGuiLocKey_WindowingPopup
@ ImGuiLocKey_TableSizeAllFit
@ ImGuiLocKey_DockingHoldShiftToDock
@ ImGuiLocKey_TableSizeOne
int ImGuiLogFlags
ImGuiAxis
@ ImGuiAxis_None
@ ImGuiAxis_X
@ ImGuiAxis_Y
@ ImGuiButtonFlags_AllowOverlap
@ ImGuiButtonFlags_FlattenChildren
@ ImGuiButtonFlags_NoNavFocus
#define IMGUI_DEBUG_LOG_INPUTROUTING(...)
static IM_MSVC_RUNTIME_CHECKS_OFF char ImToUpper(char c)
#define IM_DEBUG_BREAK()
static float ImFloor(float f)
@ ImGuiDebugLogFlags_EventDocking
@ ImGuiDebugLogFlags_EventViewport
@ ImGuiDebugLogFlags_EventSelection
@ ImGuiDebugLogFlags_EventClipper
@ ImGuiDebugLogFlags_OutputToTTY
@ ImGuiDebugLogFlags_EventError
@ ImGuiDebugLogFlags_EventFocus
@ ImGuiDebugLogFlags_EventActiveId
@ ImGuiDebugLogFlags_OutputToTestEngine
@ ImGuiDebugLogFlags_EventNav
@ ImGuiDebugLogFlags_EventIO
@ ImGuiDebugLogFlags_EventInputRouting
@ ImGuiDebugLogFlags_EventMask_
@ ImGuiDebugLogFlags_None
@ ImGuiDebugLogFlags_EventFont
@ ImGuiDebugLogFlags_EventPopup
FILE * ImFileHandle
#define ImGuiKey_NavGamepadCancel
#define IMGUI_DEBUG_LOG_CLIPPER(...)
@ ImGuiDockNodeState_Unknown
@ ImGuiDockNodeState_HostWindowVisible
@ ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing
@ ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow
IMGUI_API char * ImStrdup(const char *str)
Definition: imgui.cpp:2125
#define ImGuiKey_NavGamepadActivate
#define IMGUI_DEBUG_LOG_ACTIVEID(...)
static T ImClamp(T v, T mn, T mx)
#define DOCKING_HOST_DRAW_CHANNEL_FG
#define ImGuiKeyOwner_NoOwner
@ ImGuiFocusRequestFlags_RestoreFocusedChild
@ ImGuiFocusRequestFlags_UnlessBelowModal
@ ImGuiFocusRequestFlags_None
@ ImGuiTooltipFlags_None
@ ImGuiTooltipFlags_OverridePrevious
static void ImQsort(void *base, size_t count, size_t size_of_element, int(IMGUI_CDECL *compare_func)(void const *, void const *))
@ ImGuiInputFlags_RepeatUntilKeyModsChangeFromNone
@ ImGuiInputFlags_RepeatRateMask_
@ ImGuiInputFlags_SupportedByIsMouseClicked
@ ImGuiInputFlags_RepeatUntilMask_
@ ImGuiInputFlags_CondActive
@ ImGuiInputFlags_RepeatRateNavTweak
@ ImGuiInputFlags_CondDefault_
@ ImGuiInputFlags_SupportedByShortcut
@ ImGuiInputFlags_SupportedBySetItemKeyOwner
@ ImGuiInputFlags_RepeatRateDefault
@ ImGuiInputFlags_LockUntilRelease
@ ImGuiInputFlags_RepeatMask_
@ ImGuiInputFlags_SupportedBySetNextItemShortcut
@ ImGuiInputFlags_CondHovered
@ ImGuiInputFlags_LockThisFrame
@ ImGuiInputFlags_CondMask_
@ ImGuiInputFlags_SupportedByIsKeyPressed
@ ImGuiInputFlags_RepeatUntilOtherKeyPress
@ ImGuiInputFlags_RouteTypeMask_
@ ImGuiInputFlags_RepeatRateNavMove
@ ImGuiInputFlags_SupportedBySetKeyOwner
@ ImGuiInputFlags_RepeatUntilKeyModsChange
static T ImMax(T lhs, T rhs)
@ ImGuiItemStatusFlags_ToggledSelection
@ ImGuiItemStatusFlags_HasDisplayRect
@ ImGuiItemStatusFlags_HoveredRect
@ ImGuiItemStatusFlags_Deactivated
@ ImGuiItemStatusFlags_HasShortcut
@ ImGuiItemStatusFlags_Edited
@ ImGuiItemStatusFlags_HasDeactivated
@ ImGuiItemStatusFlags_HoveredWindow
@ ImGuiItemStatusFlags_None
@ ImGuiItemStatusFlags_HasClipRect
@ ImGuiItemStatusFlags_Visible
@ ImGuiItemStatusFlags_ToggledOpen
#define ImGuiKeyOwner_Any
@ ImGuiDockNodeFlags_NoResizeX
@ ImGuiDockNodeFlags_DockedWindowsInFocusRoute
@ ImGuiDockNodeFlags_NoDockingOverMe
@ ImGuiDockNodeFlags_NoDockingSplitOther
@ ImGuiDockNodeFlags_NoResizeY
@ ImGuiDockNodeFlags_DockSpace
@ ImGuiDockNodeFlags_SavedFlagsMask_
@ ImGuiDockNodeFlags_NoWindowMenuButton
@ ImGuiDockNodeFlags_NoDockingOverEmpty
@ ImGuiDockNodeFlags_NoDocking
@ ImGuiDockNodeFlags_SharedFlagsInheritMask_
@ ImGuiDockNodeFlags_NoDockingOverOther
@ ImGuiDockNodeFlags_CentralNode
@ ImGuiDockNodeFlags_NoTabBar
@ ImGuiDockNodeFlags_HiddenTabBar
@ ImGuiDockNodeFlags_LocalFlagsTransferMask_
@ ImGuiDockNodeFlags_NoCloseButton
#define IM_TRUNC(_VAL)
static T ImMin(T lhs, T rhs)
static float ImExponentialMovingAverage(float avg, float sample, int n)
@ ImGuiWindowRefreshFlags_TryToAvoidRefresh
@ ImGuiWindowRefreshFlags_RefreshOnHover
@ ImGuiWindowRefreshFlags_RefreshOnFocus
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS)
IMGUI_API ImGuiID ImHashStr(const char *data, size_t data_size=0, ImGuiID seed=0)
Definition: imgui.cpp:2404
@ ImGuiHoveredFlags_AllowedMaskForIsItemHovered
@ ImGuiHoveredFlags_AllowedMaskForIsWindowHovered
#define ImGuiKey_NavGamepadMenu
static float ImRound64(float f)
int ImGuiItemStatusFlags
#define ImGuiSelectionUserData_Invalid
ImGuiInputEventType
@ ImGuiInputEventType_Focus
@ ImGuiInputEventType_MouseViewport
@ ImGuiInputEventType_Text
@ ImGuiInputEventType_MouseWheel
@ ImGuiInputEventType_Key
@ ImGuiInputEventType_MousePos
@ ImGuiInputEventType_MouseButton
#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB, _ID)
ImGuiInputSource
@ ImGuiInputSource_Mouse
@ ImGuiInputSource_Gamepad
@ ImGuiInputSource_COUNT
@ ImGuiInputSource_Keyboard
@ ImGuiInputSource_None
#define ImGuiKey_NavGamepadInput
int ImGuiNavRenderCursorFlags
int ImGuiFocusRequestFlags
ImGuiPopupPositionPolicy
@ ImGuiPopupPositionPolicy_ComboBox
@ ImGuiPopupPositionPolicy_Tooltip
@ ImGuiPopupPositionPolicy_Default
#define IMGUI_DEBUG_LOG_FOCUS(...)
ImS16 ImGuiKeyRoutingIndex
#define IMGUI_DEBUG_LOG_ERROR(...)
#define ImGuiKey_Keyboard_END
#define IM_ASSERT_PARANOID(_EXPR)
static float ImTrunc64(float f)
#define ImStrlen
#define ImFabs(X)
static int ImAbs(int x)
#define IMGUI_DEBUG_LOG_NAV(...)
static unsigned int ImCountSetBits(unsigned int v)
@ ImGuiTabItemFlags_Unsorted
@ ImGuiTabItemFlags_Button
static bool ImCharIsXdigitA(char c)
#define ImGuiKey_Mouse_END
#define ImFmod(X, Y)
@ ImGuiNextItemDataFlags_None
@ ImGuiNextItemDataFlags_HasShortcut
@ ImGuiNextItemDataFlags_HasWidth
#define IM_STATIC_ASSERT(_COND)
#define IM_PI
@ ImGuiNextWindowDataFlags_HasSizeConstraint
@ ImGuiNextWindowDataFlags_HasSize
@ ImGuiNextWindowDataFlags_HasFocus
@ ImGuiNextWindowDataFlags_HasBgAlpha
@ ImGuiNextWindowDataFlags_HasViewport
@ ImGuiNextWindowDataFlags_HasChildFlags
@ ImGuiNextWindowDataFlags_HasWindowClass
@ ImGuiNextWindowDataFlags_HasContentSize
@ ImGuiNextWindowDataFlags_HasScroll
@ ImGuiNextWindowDataFlags_HasDock
@ ImGuiNextWindowDataFlags_HasCollapsed
@ ImGuiNextWindowDataFlags_HasRefreshPolicy
@ ImGuiNextWindowDataFlags_HasPos
#define IMGUI_DEBUG_LOG_VIEWPORT(...)
@ ImGuiLayoutType_Vertical
@ ImGuiLayoutType_Horizontal
int ImGuiDebugLogFlags
static bool ImCharIsBlankA(char c)
static bool ImIsFloatAboveGuaranteedIntegerPrecision(float f)
#define IM_STRINGIFY(_X)
#define IMGUI_DEBUG_LOG_POPUP(...)
@ ImGuiLogFlags_None
@ ImGuiLogFlags_OutputTTY
@ ImGuiLogFlags_OutputMask_
@ ImGuiLogFlags_OutputFile
@ ImGuiLogFlags_OutputBuffer
@ ImGuiLogFlags_OutputClipboard
@ ImGuiActivateFlags_PreferInput
@ ImGuiActivateFlags_TryToPreserveState
@ ImGuiActivateFlags_FromTabbing
@ ImGuiActivateFlags_FromShortcut
@ ImGuiActivateFlags_None
@ ImGuiActivateFlags_PreferTweak
#define IM_ROUND(_VAL)
static float ImSaturate(float f)
int ImGuiTooltipFlags
@ ImGuiNavMoveFlags_Forwarded
@ ImGuiNavMoveFlags_WrapY
@ ImGuiNavMoveFlags_IsPageMove
@ ImGuiNavMoveFlags_AlsoScoreVisibleSet
@ ImGuiNavMoveFlags_IsTabbing
@ ImGuiNavMoveFlags_AllowCurrentNavId
@ ImGuiNavMoveFlags_DebugNoResult
@ ImGuiNavMoveFlags_WrapX
@ ImGuiNavMoveFlags_NoSelect
@ ImGuiNavMoveFlags_LoopY
@ ImGuiNavMoveFlags_None
@ ImGuiNavMoveFlags_ScrollToEdgeY
@ ImGuiNavMoveFlags_WrapMask_
@ ImGuiNavMoveFlags_LoopX
@ ImGuiNavMoveFlags_FocusApi
@ ImGuiNavMoveFlags_Activate
@ ImGuiNavMoveFlags_NoClearActiveId
@ ImGuiNavMoveFlags_NoSetNavCursorVisible
int ImGuiDataAuthority
#define IM_PRId64
#define IMGUI_PAYLOAD_TYPE_WINDOW
#define DOCKING_HOST_DRAW_CHANNEL_BG
#define IMGUI_FONT_SIZE_MAX
#define ImGuiKey_NavGamepadTweakSlow
float ImTriangleArea(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c)
@ ImGuiDataAuthority_Window
@ ImGuiDataAuthority_Auto
@ ImGuiDataAuthority_DockNode
#define IM_MSVC_WARNING_SUPPRESS(XXXX)
#define IMGUI_DEBUG_LOG_IO(...)
@ ImGuiNavRenderCursorFlags_NoRounding
@ ImGuiNavRenderCursorFlags_AlwaysDraw
@ ImGuiNavRenderCursorFlags_Compact
#define ImGuiKey_Gamepad_BEGIN
#define ImGuiKey_Keyboard_BEGIN
#define ImSqrt(X)
IMGUI_API ImGuiID ImHashData(const void *data, size_t data_size, ImGuiID seed=0)
Definition: imgui.cpp:2376
@ ImGuiDataType_ID
@ ImGuiDataType_Pointer
ImGuiNavLayer
@ ImGuiNavLayer_Menu
@ ImGuiNavLayer_COUNT
@ ImGuiNavLayer_Main
#define IM_ASSERT_USER_ERROR(_EXPR, _MSG)
ImFontAtlasRectId ImFontAtlasRectId_Make(int index_idx, int gen_idx)
int ImGuiNavMoveFlags
IMGUI_API void SetCursorPosY(float local_y)
Definition: imgui.cpp:11876
IMGUI_API void AddDrawListToDrawDataEx(ImDrawData *draw_data, ImVector< ImDrawList * > *out_list, ImDrawList *draw_list)
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow *ref_window, bool restore_focus_to_window_under_popup)
Definition: imgui.cpp:12672
IMGUI_API void PushStyleVarY(ImGuiStyleVar idx, float val_y)
Definition: imgui.cpp:3619
IMGUI_API int GetFrameCount()
Definition: imgui.cpp:5113
IMGUI_API float GetCursorPosX()
Definition: imgui.cpp:11848
IMGUI_API void EndDragDropSource()
Definition: imgui.cpp:15244
IMGUI_API bool InputTextMultiline(const char *label, char *buf, size_t buf_size, const ImVec2 &size=ImVec2(0, 0), ImGuiInputTextFlags flags=0, ImGuiInputTextCallback callback=NULL, void *user_data=NULL)
IMGUI_API bool IsAnyItemHovered()
Definition: imgui.cpp:6396
IMGUI_API bool BeginItemTooltip()
Definition: imgui.cpp:12402
ImGuiWindow * GetCurrentWindowRead()
const char * LocalizeGetMsg(ImGuiLocKey key)
IMGUI_API ImGuiID DockBuilderSplitNode(ImGuiID node_id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID *out_id_at_dir, ImGuiID *out_id_at_opposite_dir)
Definition: imgui.cpp:20332
ImGuiKeyOwnerData * GetKeyOwnerData(ImGuiContext *ctx, ImGuiKey key)
IMGUI_API void RegisterUserTexture(ImTextureData *tex)
Definition: imgui.cpp:9346
IMGUI_API void EndGroup()
Definition: imgui.cpp:12085
IMGUI_API bool BeginTooltip()
Definition: imgui.cpp:12397
ImRect WindowRectAbsToRel(ImGuiWindow *window, const ImRect &r)
IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float &out_r, float &out_g, float &out_b)
Definition: imgui.cpp:2785
IMGUI_API void SetScrollX(float scroll_x)
Definition: imgui.cpp:12317
IMGUI_API void PopTextWrapPos()
Definition: imgui.cpp:8694
IMGUI_API bool IsMouseReleasedWithDelay(ImGuiMouseButton button, float delay)
Definition: imgui.cpp:10267
IMGUI_API ImVec2 GetContentRegionMax()
Definition: imgui.cpp:12035
static void DockNodeWindowMenuUpdate(ImGuiDockNode *node, ImGuiTabBar *tab_bar)
Definition: imgui.cpp:18798
IMGUI_API void ShowFontSelector(const char *label)
Definition: imgui.cpp:23634
IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)
Definition: imgui.cpp:12734
IMGUI_API void TableHeadersRow()
IMGUI_API bool ItemAdd(const ImRect &bb, ImGuiID id, const ImRect *nav_bb=NULL, ImGuiItemFlags extra_flags=0)
Definition: imgui.cpp:11620
IMGUI_API ImVec2 ScrollToRectEx(ImGuiWindow *window, const ImRect &rect, ImGuiScrollFlags flags=0)
Definition: imgui.cpp:12207
IMGUI_API bool IsAnyMouseDown()
Definition: imgui.cpp:10374
IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul=1.0f)
Definition: imgui.cpp:3465
IMGUI_API bool IsPopupOpen(const char *str_id, ImGuiPopupFlags flags=0)
Definition: imgui.cpp:12532
IMGUI_API bool IsItemVisible()
Definition: imgui.cpp:6414
IMGUI_API void RemoveSettingsHandler(const char *type_name)
Definition: imgui.cpp:15761
IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold=-1.0f)
Definition: imgui.cpp:10327
IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow **windows, int windows_size, ImGuiWindow *parent_in_begin_stack)
Definition: imgui.cpp:23123
static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow *nav_window)
Definition: imgui.cpp:13925
IMGUI_API void SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect &rect_rel)
Definition: imgui.cpp:13466
IMGUI_API ImGuiID GetItemID()
Definition: imgui.cpp:6460
IMGUI_API void TextV(const char *fmt, va_list args) IM_FMTLIST(1)
ImRect WindowRectRelToAbs(ImGuiWindow *window, const ImRect &r)
IMGUI_API bool BeginPopup(const char *str_id, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:12830
IMGUI_API const char * GetClipboardText()
Definition: imgui.cpp:5056
IMGUI_API bool IsItemClicked(ImGuiMouseButton mouse_button=0)
Definition: imgui.cpp:6370
IMGUI_API void PushClipRect(const ImVec2 &clip_rect_min, const ImVec2 &clip_rect_max, bool intersect_with_current_clip_rect)
Definition: imgui.cpp:5894
IMGUI_API void SetWindowFontScale(float scale)
Definition: imgui.cpp:9123
IMGUI_API void SetNextItemWidth(float item_width)
Definition: imgui.cpp:11907
static void DockNodeUpdateFlagsAndCollapse(ImGuiDockNode *node)
Definition: imgui.cpp:18284
IMGUI_API void DebugRenderKeyboardPreview(ImDrawList *draw_list)
Definition: imgui.cpp:21393
IMGUI_API void PopStyleVar(int count=1)
Definition: imgui.cpp:3647
IMGUI_API void SeparatorTextEx(ImGuiID id, const char *label, const char *label_end, float extra_width)
IMGUI_API void ActivateItemByID(ImGuiID id)
Definition: imgui.cpp:9200
IMGUI_API void SetNextWindowSizeConstraints(const ImVec2 &size_min, const ImVec2 &size_max, ImGuiSizeCallback custom_callback=NULL, void *custom_callback_data=NULL)
Definition: imgui.cpp:9007
IMGUI_API void NavClearPreferredPosForAxis(ImGuiAxis axis)
Definition: imgui.cpp:13460
static void DockSettingsHandler_ReadLine(ImGuiContext *, ImGuiSettingsHandler *, void *entry, const char *line)
Definition: imgui.cpp:20924
IMGUI_API ImFontBaked * GetFontBaked()
Definition: imgui.cpp:9103
IMGUI_API void BeginDockableDragDropTarget(ImGuiWindow *window)
Definition: imgui.cpp:20758
IMGUI_API const ImGuiPayload * GetDragDropPayload()
Definition: imgui.cpp:15426
IMGUI_API void ClearActiveID()
Definition: imgui.cpp:4664
IMGUI_API ImGuiWindowSettings * FindWindowSettingsByID(ImGuiID id)
Definition: imgui.cpp:15926
IMGUI_API bool BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags)
Definition: imgui.cpp:12409
IMGUI_API void Separator()
IMGUI_API ImGuiWindow * FindBlockingModal(ImGuiWindow *window)
Definition: imgui.cpp:12577
IMGUI_API ImGuiMultiSelectIO * EndMultiSelect()
IMGUI_API ImGuiViewport * FindViewportByID(ImGuiID id)
Definition: imgui.cpp:16128
IMGUI_API void DebugNodeTypingSelectState(ImGuiTypingSelectState *state)
IMGUI_API void Initialize()
Definition: imgui.cpp:4305
IMGUI_API void GetTypematicRepeatRate(ImGuiInputFlags flags, float *repeat_delay, float *repeat_rate)
Definition: imgui.cpp:9845
IMGUI_API const char * GetKeyName(ImGuiKey key)
Definition: imgui.cpp:9792
IMGUI_API bool ItemHoverable(const ImRect &bb, ImGuiID id, ImGuiItemFlags item_flags)
Definition: imgui.cpp:4855
static bool DockNodeIsDropAllowed(ImGuiWindow *host_window, ImGuiWindow *payload_window)
Definition: imgui.cpp:19189
bool IsNamedKey(ImGuiKey key)
IMGUI_API ImGuiID AddContextHook(ImGuiContext *context, const ImGuiContextHook *hook)
Definition: imgui.cpp:4468
IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2 &image_size, const ImVec2 &uv0=ImVec2(0, 0), const ImVec2 &uv1=ImVec2(1, 1))
float GetRoundedFontSize(float size)
IMGUI_API void BringWindowToDisplayFront(ImGuiWindow *window)
Definition: imgui.cpp:13251
static void WindowSelectViewport(ImGuiWindow *window)
Definition: imgui.cpp:16648
IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2 &pos, ImGuiDockNode *dock_node)
bool IsKeyboardKey(ImGuiKey key)
IMGUI_API void RegisterFontAtlas(ImFontAtlas *atlas)
Definition: imgui.cpp:9359
IMGUI_API void UnregisterUserTexture(ImTextureData *tex)
Definition: imgui.cpp:9353
IMGUI_API bool TreeNodeEx(const char *label, ImGuiTreeNodeFlags flags=0)
IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow *window, int n)
Definition: imgui.cpp:6982
static bool UpdateTryMergeWindowIntoHostViewports(ImGuiWindow *window)
Definition: imgui.cpp:16227
IMGUI_API bool IsMousePosValid(const ImVec2 *mouse_pos=NULL)
Definition: imgui.cpp:10363
IMGUI_API ImVec2 GetMouseDragDelta(ImGuiMouseButton button=0, float lock_threshold=-1.0f)
Definition: imgui.cpp:10386
IMGUI_API void RenderDragDropTargetRect(const ImRect &bb, const ImRect &item_clip_rect)
Definition: imgui.cpp:15411
static void DockContextQueueNotifyRemovedNode(ImGuiContext *ctx, ImGuiDockNode *node)
Definition: imgui.cpp:17712
IMGUI_API void EndFrame()
Definition: imgui.cpp:6032
IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList *out_draw_list, const ImDrawList *draw_list, const ImDrawCmd *draw_cmd, bool show_mesh, bool show_aabb)
Definition: imgui.cpp:22667
IMGUI_API void DockContextEndFrame(ImGuiContext *ctx)
Definition: imgui.cpp:17462
ImGuiKey MouseButtonToKey(ImGuiMouseButton button)
IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)
Definition: imgui.cpp:13898
IMGUI_API void UnregisterFontAtlas(ImFontAtlas *atlas)
Definition: imgui.cpp:9369
static void DockContextProcessDock(ImGuiContext *ctx, ImGuiDockRequest *req)
Definition: imgui.cpp:17720
IMGUI_API const char * GetStyleColorName(ImGuiCol idx)
Definition: imgui.cpp:3668
IMGUI_API void DebugNodeTexture(ImTextureData *tex, int int_id, const ImFontAtlasRect *highlight_rect=NULL)
Definition: imgui.cpp:21699
IMGUI_API void MemFree(void *ptr)
Definition: imgui.cpp:5020
IMGUI_API void BeginDisabledOverrideReenable()
Definition: imgui.cpp:8665
IMGUI_API void StyleColorsDark(ImGuiStyle *dst=NULL)
Definition: imgui_draw.cpp:184
IMGUI_API const char * SaveIniSettingsToMemory(size_t *out_ini_size=NULL)
Definition: imgui.cpp:15888
IMGUI_API void RenderNavCursor(const ImRect &bb, ImGuiID id, ImGuiNavRenderCursorFlags flags=ImGuiNavRenderCursorFlags_None)
Definition: imgui.cpp:3928
IMGUI_API void PushID(const char *str_id)
Definition: imgui.cpp:9560
IMGUI_API void FocusWindow(ImGuiWindow *window, ImGuiFocusRequestFlags flags=0)
Definition: imgui.cpp:13309
static const char * DockNodeGetHostWindowTitle(ImGuiDockNode *node, char *buf, int buf_size)
Definition: imgui.cpp:17286
IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow *window)
Definition: imgui.cpp:4600
static void DockNodeTreeUpdatePosSize(ImGuiDockNode *node, ImVec2 pos, ImVec2 size, ImGuiDockNode *only_write_to_single_node=NULL)
Definition: imgui.cpp:19638
IMGUI_API bool SplitterBehavior(const ImRect &bb, ImGuiID id, ImGuiAxis axis, float *size1, float *size2, float min_size1, float min_size2, float hover_extend=0.0f, float hover_visibility_delay=0.0f, ImU32 bg_col=0)
IMGUI_API void SetCurrentContext(ImGuiContext *ctx)
Definition: imgui.cpp:4007
IMGUI_API ImGuiID DockSpaceOverViewport(ImGuiID dockspace_id=0, const ImGuiViewport *viewport=NULL, ImGuiDockNodeFlags flags=0, const ImGuiWindowClass *window_class=NULL)
Definition: imgui.cpp:20059
IMGUI_API bool BeginPopupMenuEx(ImGuiID id, const char *label, ImGuiWindowFlags extra_window_flags)
Definition: imgui.cpp:12811
IMGUI_API void SetWindowHiddenAndSkipItemsForCurrentFrame(ImGuiWindow *window)
Definition: imgui.cpp:8954
IMGUI_API ImDrawListSharedData * GetDrawListSharedData()
Definition: imgui.cpp:5156
IMGUI_API bool IsWindowCollapsed()
Definition: imgui.cpp:8965
IMGUI_API bool BeginTooltipHidden()
Definition: imgui.cpp:15110
IMGUI_API bool TextLinkOpenURL(const char *label, const char *url=NULL)
IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button)
Definition: imgui.cpp:10275
static void NavUpdateAnyRequestFlag()
Definition: imgui.cpp:13969
IMGUI_API bool TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id)
Definition: imgui.cpp:10124
IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat=false)
Definition: imgui.cpp:10223
IMGUI_API bool IsItemActive()
Definition: imgui.cpp:6321
IMGUI_API void SetNavCursorVisible(bool visible)
Definition: imgui.cpp:13423
ImVec2 WindowPosAbsToRel(ImGuiWindow *window, const ImVec2 &p)
IMGUI_API void LogFinish()
Definition: imgui.cpp:15629
IMGUI_API ImGuiWindowSettings * CreateNewWindowSettings(const char *name)
Definition: imgui.cpp:15901
IMGUI_API bool IsItemToggledOpen()
Definition: imgui.cpp:6375
IMGUI_API const ImGuiPlatformMonitor * GetViewportPlatformMonitor(ImGuiViewport *viewport)
Definition: imgui.cpp:17063
IMGUI_API ImVec2 GetCursorPos()
Definition: imgui.cpp:11842
IMGUI_API void EndErrorTooltip()
Definition: imgui.cpp:11593
IMGUI_API ImVec2 GetFontTexUvWhitePixel()
Definition: imgui.cpp:9116
IMGUI_API void TreePush(const char *str_id)
IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow *window)
Definition: imgui.cpp:13077
IMGUI_API void SetTooltip(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:12462
IMGUI_API ImGuiIO & GetIO()
Definition: imgui.cpp:5074
IMGUI_API void SetScrollHereX(float center_x_ratio=0.5f)
Definition: imgui.cpp:12368
IMGUI_API void DebugTextEncoding(const char *text)
Definition: imgui.cpp:21443
IMGUI_API void SetItemAllowOverlap()
Definition: imgui.cpp:6438
IMGUI_API ImVec2 GetItemRectSize()
Definition: imgui.cpp:6478
IMGUI_API ImGuiID GetID(const char *str_id)
Definition: imgui.cpp:9640
IMGUI_API void TabBarRemoveTab(ImGuiTabBar *tab_bar, ImGuiID tab_id)
IMGUI_API void EndDisabledOverrideReenable()
Definition: imgui.cpp:8676
static void ItemHandleShortcut(ImGuiID id)
Definition: imgui.cpp:11058
IMGUI_API void ImageWithBg(ImTextureRef tex_ref, const ImVec2 &image_size, const ImVec2 &uv0=ImVec2(0, 0), const ImVec2 &uv1=ImVec2(1, 1), const ImVec4 &bg_col=ImVec4(0, 0, 0, 0), const ImVec4 &tint_col=ImVec4(1, 1, 1, 1))
IMGUI_API void TranslateWindowsInViewport(ImGuiViewportP *viewport, const ImVec2 &old_pos, const ImVec2 &new_pos, const ImVec2 &old_size, const ImVec2 &new_size)
Definition: imgui.cpp:16235
IMGUI_API void BringWindowToDisplayBack(ImGuiWindow *window)
Definition: imgui.cpp:13266
IMGUI_API void SetNextWindowScroll(const ImVec2 &scroll)
Definition: imgui.cpp:9025
IMGUI_API void RenderRectFilledWithHole(ImDrawList *draw_list, const ImRect &outer, const ImRect &inner, ImU32 col, float rounding)
IMGUI_API void SeparatorText(const char *label)
IMGUI_API void SetItemTooltip(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:12480
IMGUI_API void TextColored(const ImVec4 &col, const char *fmt,...) IM_FMTARGS(2)
static void UpdateFontsEndFrame()
Definition: imgui.cpp:9332
IMGUI_API void SetItemDefaultFocus()
Definition: imgui.cpp:9242
IMGUI_API void FindHoveredWindowEx(const ImVec2 &pos, bool find_first_and_in_any_viewport, ImGuiWindow **out_hovered_window, ImGuiWindow **out_hovered_window_under_moving_window)
Definition: imgui.cpp:6252
IMGUI_API bool Button(const char *label, const ImVec2 &size=ImVec2(0, 0))
IMGUI_API void DebugTextUnformattedWithLocateItem(const char *line_begin, const char *line_end)
Definition: imgui.cpp:23280
IMGUI_API void OpenPopupOnItemClick(const char *str_id=NULL, ImGuiPopupFlags popup_flags=1)
Definition: imgui.cpp:12905
IMGUI_API void SetTooltipV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:12470
IMGUI_API const ImGuiStyleVarInfo * GetStyleVarInfo(ImGuiStyleVar idx)
Definition: imgui.cpp:3584
IMGUI_API ImGuiID GetKeyOwner(ImGuiKey key)
Definition: imgui.cpp:10920
bool DockNodeIsInHierarchyOf(ImGuiDockNode *node, ImGuiDockNode *parent)
IMGUI_API void DockContextInitialize(ImGuiContext *ctx)
Definition: imgui.cpp:17336
IMGUI_API ImGuiMouseCursor GetMouseCursor()
Definition: imgui.cpp:10411
IMGUI_API void UpdateMouseMovingWindowNewFrame()
Definition: imgui.cpp:5213
IMGUI_API float GetScrollY()
Definition: imgui.cpp:12285
IMGUI_API ImVec2 GetItemRectMax()
Definition: imgui.cpp:6472
static void DockNodeCalcTabBarLayout(const ImGuiDockNode *node, ImRect *out_title_rect, ImRect *out_tab_bar_rect, ImVec2 *out_window_menu_button_pos, ImVec2 *out_close_button_pos)
Definition: imgui.cpp:19206
IMGUI_API ImGuiID DockSpace(ImGuiID dockspace_id, const ImVec2 &size=ImVec2(0, 0), ImGuiDockNodeFlags flags=0, const ImGuiWindowClass *window_class=NULL)
Definition: imgui.cpp:19949
IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond=0)
Definition: imgui.cpp:9032
IMGUI_API void NavHighlightActivated(ImGuiID id)
Definition: imgui.cpp:13453
IMGUI_API ImGuiPlatformIO & GetPlatformIO()
Definition: imgui.cpp:5087
static void RenderWindowTitleBarContents(ImGuiWindow *window, const ImRect &title_bar_rect, const char *name, bool *p_open)
Definition: imgui.cpp:7429
IMGUI_API bool ErrorLog(const char *msg)
Definition: imgui.cpp:11471
static bool NavScoreItem(ImGuiNavItemData *result)
Definition: imgui.cpp:13527
IMGUI_API double GetTime()
Definition: imgui.cpp:5108
IMGUI_API bool NavMoveRequestButNoResultYet()
Definition: imgui.cpp:13837
IMGUI_API void DockContextNewFrameUpdateDocking(ImGuiContext *ctx)
Definition: imgui.cpp:17429
static ImVec2 NavCalcPreferredRefPos()
Definition: imgui.cpp:14023
static ImGuiDockNode * DockNodeTreeFindFallbackLeafNode(ImGuiDockNode *node)
Definition: imgui.cpp:19866
IMGUI_API ImVec2 GetContentRegionAvail()
Definition: imgui.cpp:12023
IMGUI_API ImVec2 GetWindowPos()
Definition: imgui.cpp:8845
static void UpdateViewportPlatformMonitor(ImGuiViewportP *viewport)
Definition: imgui.cpp:17057
IMGUI_API void SetScrollY(float scroll_y)
Definition: imgui.cpp:12323
IMGUI_API void TreePop()
IMGUI_API void BeginGroup()
Definition: imgui.cpp:12056
static void DockNodeUpdateVisibleFlag(ImGuiDockNode *node)
Definition: imgui.cpp:18376
IMGUI_API void NavMoveRequestCancel()
Definition: imgui.cpp:13890
IMGUI_API ImFont * GetFont()
Definition: imgui.cpp:9098
IMGUI_API bool BeginPopupContextItem(const char *str_id=NULL, ImGuiPopupFlags popup_flags=1)
Definition: imgui.cpp:12934
IMGUI_API ImGuiKeyRoutingData * GetShortcutRoutingData(ImGuiKeyChord key_chord)
Definition: imgui.cpp:9927
IMGUI_API float GetWindowHeight()
Definition: imgui.cpp:8839
static void UpdateMouseWheel()
Definition: imgui.cpp:10650
IMGUI_API bool SetDragDropPayload(const char *type, const void *data, size_t sz, ImGuiCond cond=0)
Definition: imgui.cpp:15260
IMGUI_API void RenderBullet(ImDrawList *draw_list, ImVec2 pos, ImU32 col)
IMGUI_API void DockNodeWindowMenuHandler_Default(ImGuiContext *ctx, ImGuiDockNode *node, ImGuiTabBar *tab_bar)
Definition: imgui.cpp:18773
IMGUI_API const char * GetKeyChordName(ImGuiKeyChord key_chord)
Definition: imgui.cpp:9807
IMGUI_API float GetWindowWidth()
Definition: imgui.cpp:8833
IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings *settings)
IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat=true)
Definition: imgui.cpp:10149
IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate)
Definition: imgui.cpp:9858
IMGUI_API bool IsWindowWithinBeginStackOf(ImGuiWindow *window, ImGuiWindow *potential_parent)
Definition: imgui.cpp:8738
static void DockNodeUpdateForRootNode(ImGuiDockNode *node)
Definition: imgui.cpp:18397
IMGUI_API void TableSettingsAddSettingsHandler()
IMGUI_API ImDrawList * GetBackgroundDrawList(ImGuiViewport *viewport=NULL)
Definition: imgui.cpp:5142
static void DockNodeTreeUpdateSplitter(ImGuiDockNode *node)
Definition: imgui.cpp:19749
IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond=0)
IMGUI_API void TableSetupColumn(const char *label, ImGuiTableColumnFlags flags=0, float init_width_or_weight=0.0f, ImGuiID user_id=0)
IMGUI_API void PushItemWidth(float item_width)
Definition: imgui.cpp:11915
static void NavUpdateCreateTabbingRequest()
Definition: imgui.cpp:14428
static void DockNodeUpdateTabBar(ImGuiDockNode *node, ImGuiWindow *host_window)
Definition: imgui.cpp:18861
IMGUI_API void ItemSize(const ImVec2 &size, float text_baseline_y=-1.0f)
Definition: imgui.cpp:11758
IMGUI_API void LoadIniSettingsFromDisk(const char *ini_filename)
Definition: imgui.cpp:15788
IMGUI_API void DebugNodeMultiSelectState(ImGuiMultiSelectState *state)
IMGUI_API void LogToBuffer(int auto_open_depth=-1)
Definition: imgui.cpp:15621
IMGUI_API bool TreeNode(const char *label)
IMGUI_API bool TabItemEx(ImGuiTabBar *tab_bar, const char *label, bool *p_open, ImGuiTabItemFlags flags, ImGuiWindow *docked_window)
IMGUI_API void TableGcCompactSettings()
static int FindPlatformMonitorForRect(const ImRect &r)
Definition: imgui.cpp:17025
static void RenderWindowDecorations(ImGuiWindow *window, const ImRect &title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size)
Definition: imgui.cpp:7279
IMGUI_API bool CloseButton(ImGuiID id, const ImVec2 &pos)
static void NavUpdateCancelRequest()
Definition: imgui.cpp:14573
ImGuiKeyChord FixupKeyChord(ImGuiKeyChord key_chord)
Definition: imgui.cpp:9744
IMGUI_API ImGuiContext * CreateContext(ImFontAtlas *shared_font_atlas=NULL)
Definition: imgui.cpp:4031
static void UpdateTexturesNewFrame()
Definition: imgui.cpp:5445
IMGUI_API void SetCurrentViewport(ImGuiWindow *window, ImGuiViewportP *viewport)
Definition: imgui.cpp:16146
IMGUI_API void NavInitRequestApplyResult()
Definition: imgui.cpp:14257
IMGUI_API void SetCursorPos(const ImVec2 &local_pos)
Definition: imgui.cpp:11860
IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0)
Definition: imgui.cpp:13173
static void DockNodeUpdate(ImGuiDockNode *node)
Definition: imgui.cpp:18448
IMGUI_API ImGuiDockNode * DockContextFindNodeByID(ImGuiContext *ctx, ImGuiID id)
Definition: imgui.cpp:17478
IMGUI_API ImGuiViewport * FindViewportByPlatformHandle(void *platform_handle)
Definition: imgui.cpp:16137
IMGUI_API void End()
Definition: imgui.cpp:8537
IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void *data_id, const void *data_id_end)
Definition: imgui.cpp:23465
IMGUI_API void Scrollbar(ImGuiAxis axis)
static void UpdateDebugToolFlashStyleColor()
Definition: imgui.cpp:21498
static void UpdateTexturesEndFrame()
Definition: imgui.cpp:5469
IMGUI_API void SetNavCursorVisibleAfterMove()
Definition: imgui.cpp:13432
IMGUI_API bool IsItemActivated()
Definition: imgui.cpp:6329
IMGUI_API bool IsRectVisible(const ImVec2 &size)
Definition: imgui.cpp:9272
IMGUI_API bool Checkbox(const char *label, bool *v)
IMGUI_API bool SliderInt(const char *label, int *v, int v_min, int v_max, const char *format="%d", ImGuiSliderFlags flags=0)
IMGUI_API bool Begin(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:7586
static void DockSettingsHandler_ApplyAll(ImGuiContext *, ImGuiSettingsHandler *)
Definition: imgui.cpp:20907
IMGUI_API bool Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags=0)
Definition: imgui.cpp:11082
IMGUI_API const char * TabBarGetTabName(ImGuiTabBar *tab_bar, ImGuiTabItem *tab)
static void NavEndFrame()
Definition: imgui.cpp:14701
IMGUI_API bool SmallButton(const char *label)
IMGUI_API void SetStateStorage(ImGuiStorage *storage)
Definition: imgui.cpp:9260
IMGUI_API void NavUpdateCurrentWindowIsScrollPushableX()
Definition: imgui.cpp:13686
IMGUI_API const ImGuiPayload * AcceptDragDropPayload(const char *type, ImGuiDragDropFlags flags=0)
Definition: imgui.cpp:15369
IMGUI_API ImGuiTabItem * TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar *tab_bar)
IMGUI_API void SetActiveIdUsingAllKeyboardKeys()
Definition: imgui.cpp:6451
IMGUI_API bool DockNodeBeginAmendTabBar(ImGuiDockNode *node)
Definition: imgui.cpp:18815
IMGUI_API void DebugLocateItem(ImGuiID target_id)
Definition: imgui.cpp:23339
static void NavRestoreLayer(ImGuiNavLayer layer)
Definition: imgui.cpp:13946
static void NavUpdateWindowingOverlay()
Definition: imgui.cpp:15052
static void UpdateDebugToolStackQueries()
Definition: imgui.cpp:23425
IMGUI_API void CallContextHooks(ImGuiContext *context, ImGuiContextHookType type)
Definition: imgui.cpp:4489
IMGUI_API void BeginDocked(ImGuiWindow *window, bool *p_open)
Definition: imgui.cpp:20600
static void DockSettingsRenameNodeReferences(ImGuiID old_node_id, ImGuiID new_node_id)
Definition: imgui.cpp:20854
IMGUI_API void ClosePopupsExceptModals()
Definition: imgui.cpp:12719
IMGUI_API void SetCursorScreenPos(const ImVec2 &pos)
Definition: imgui.cpp:11832
IMGUI_API void EndCombo()
static void DockContextBuildAddWindowsToNodes(ImGuiContext *ctx, ImGuiID root_id)
Definition: imgui.cpp:17651
IMGUI_API const char * GetVersion()
Definition: imgui.cpp:5069
IMGUI_API void DockContextShutdown(ImGuiContext *ctx)
Definition: imgui.cpp:17355
IMGUI_API bool IsItemEdited()
Definition: imgui.cpp:6420
IMGUI_API void SetWindowSize(const ImVec2 &size, ImGuiCond cond=0)
Definition: imgui.cpp:8923
IMGUI_API bool ButtonBehavior(const ImRect &bb, ImGuiID id, bool *out_hovered, bool *out_held, ImGuiButtonFlags flags=0)
IMGUI_API ImVec2 GetItemRectMin()
Definition: imgui.cpp:6466
int DockNodeGetDepth(const ImGuiDockNode *node)
IMGUI_API void PopFocusScope()
Definition: imgui.cpp:9142
IMGUI_API float CalcWrapWidthForPos(const ImVec2 &pos, float wrap_pos_x)
Definition: imgui.cpp:4984
IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP *viewport, float scale)
Definition: imgui.cpp:16255
IMGUI_API void LogSetNextTextDecoration(const char *prefix, const char *suffix)
Definition: imgui.cpp:15568
IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio=0.5f)
Definition: imgui.cpp:12361
static void NavUpdateCreateWrappingRequest()
Definition: imgui.cpp:14716
IMGUI_API bool IsDragDropPayloadBeingAccepted()
Definition: imgui.cpp:15363
IMGUI_API bool BeginPopupContextVoid(const char *str_id=NULL, ImGuiPopupFlags popup_flags=1)
Definition: imgui.cpp:12962
IMGUI_API void LocalizeRegisterEntries(const ImGuiLocEntry *entries, int count)
Definition: imgui.cpp:16086
IMGUI_API void DockContextRebuildNodes(ImGuiContext *ctx)
Definition: imgui.cpp:17373
IMGUI_API void TabBarQueueFocus(ImGuiTabBar *tab_bar, ImGuiTabItem *tab)
IMGUI_API void DebugNodeColumns(ImGuiOldColumns *columns)
Definition: imgui.cpp:22473
IMGUI_API void DebugNodePlatformMonitor(ImGuiPlatformMonitor *monitor, const char *label, int idx)
Definition: imgui.cpp:23014
static void DockContextRemoveNode(ImGuiContext *ctx, ImGuiDockNode *node, bool merge_sibling_into_parent_node)
Definition: imgui.cpp:17510
static void NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags)
Definition: imgui.cpp:13778
IMGUI_API void RenderPlatformWindowsDefault(void *platform_render_arg=NULL, void *renderer_render_arg=NULL)
Definition: imgui.cpp:16988
static void RenderDimmedBackgrounds()
Definition: imgui.cpp:5974
IMGUI_API bool RadioButton(const char *label, bool active)
IMGUI_API ImGuiWindow * GetTopMostPopupModal()
Definition: imgui.cpp:12542
IMGUI_API void TableEndRow(ImGuiTable *table)
IMGUI_API void Indent(float indent_w=0.0f)
Definition: imgui.cpp:11890
IMGUI_API ImGuiKeyData * GetKeyData(ImGuiContext *ctx, ImGuiKey key)
Definition: imgui.cpp:9753
static void DockContextBuildNodesFromSettings(ImGuiContext *ctx, ImGuiDockNodeSettings *node_settings_array, int node_settings_count)
Definition: imgui.cpp:17621
IMGUI_API bool BeginPopupModal(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:12847
IMGUI_API bool IsWindowNavFocusable(ImGuiWindow *window)
Definition: imgui.cpp:14778
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders=true, float rounding=0.0f)
Definition: imgui.cpp:3903
IMGUI_API void PushMultiItemsWidths(int components, float width_full)
Definition: imgui.cpp:11924
IMGUI_API void DebugBreakButtonTooltip(bool keyboard_only, const char *description_of_location)
Definition: imgui.cpp:22423
IMGUI_API void UpdateMouseMovingWindowEndFrame()
Definition: imgui.cpp:5277
IMGUI_API float GetScrollX()
Definition: imgui.cpp:12279
static void * DockSettingsHandler_ReadOpen(ImGuiContext *, ImGuiSettingsHandler *, const char *name)
Definition: imgui.cpp:20917
IMGUI_API ImGuiViewportP * FindHoveredViewportFromPlatformWindowStack(const ImVec2 &mouse_platform_pos)
Definition: imgui.cpp:16274
static void RenderWindowOuterBorders(ImGuiWindow *window)
Definition: imgui.cpp:7250
IMGUI_API void RenderTextClippedEx(ImDrawList *draw_list, const ImVec2 &pos_min, const ImVec2 &pos_max, const char *text, const char *text_end, const ImVec2 *text_size_if_known, const ImVec2 &align=ImVec2(0, 0), const ImRect *clip_rect=NULL)
Definition: imgui.cpp:3805
IMGUI_API void LogToClipboard(int auto_open_depth=-1)
Definition: imgui.cpp:15613
static void DockSettingsHandler_ClearAll(ImGuiContext *, ImGuiSettingsHandler *)
Definition: imgui.cpp:20899
IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow *window)
Definition: imgui.cpp:13056
IMGUI_API void PushTextWrapPos(float wrap_local_pos_x=0.0f)
Definition: imgui.cpp:8686
IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in)
Definition: imgui.cpp:2741
static void DockSettingsRemoveNodeReferences(ImGuiID *node_ids, int node_ids_count)
Definition: imgui.cpp:20871
IMGUI_API const char * FindRenderedTextEnd(const char *text, const char *text_end=NULL)
Definition: imgui.cpp:3745
IMGUI_API void DebugLocateItemOnHover(ImGuiID target_id)
Definition: imgui.cpp:23348
static void DockNodeRemoveWindow(ImGuiDockNode *node, ImGuiWindow *window, ImGuiID save_dock_id)
Definition: imgui.cpp:18096
IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button=0)
Definition: imgui.cpp:10399
IMGUI_API void SetItemTooltipV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:12489
IMGUI_API ImDrawList * GetForegroundDrawList(ImGuiViewport *viewport=NULL)
Definition: imgui.cpp:5149
IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col)
Definition: imgui.cpp:3499
IMGUI_API void RenderTextEllipsis(ImDrawList *draw_list, const ImVec2 &pos_min, const ImVec2 &pos_max, float ellipsis_max_x, const char *text, const char *text_end, const ImVec2 *text_size_if_known)
Definition: imgui.cpp:3852
IMGUI_API ImVec2 GetWindowContentRegionMin()
Definition: imgui.cpp:12040
static void SetLastItemDataForChildWindowItem(ImGuiWindow *window, const ImRect &rect)
Definition: imgui.cpp:4978
IMGUI_API void LogRenderedText(const ImVec2 *ref_pos, const char *text, const char *text_end=NULL)
Definition: imgui.cpp:15490
IMGUI_API void BeginDockableDragDropSource(ImGuiWindow *window)
Definition: imgui.cpp:20726
IMGUI_API bool BeginTable(const char *str_id, int columns, ImGuiTableFlags flags=0, const ImVec2 &outer_size=ImVec2(0.0f, 0.0f), float inner_width=0.0f)
IMGUI_API void SetNextWindowDockID(ImGuiID dock_id, ImGuiCond cond=0)
Definition: imgui.cpp:9055
static void DockNodeMoveChildNodes(ImGuiDockNode *dst_node, ImGuiDockNode *src_node)
Definition: imgui.cpp:18165
IMGUI_API void LogButtons()
Definition: imgui.cpp:15665
static int DockNodeGetTabOrder(ImGuiWindow *window)
Definition: imgui.cpp:18022
IMGUI_API ImVec2 GetKeyMagnitude2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down)
Definition: imgui.cpp:9869
IMGUI_API ImGuiViewport * GetMainViewport()
Definition: imgui.cpp:16121
IMGUI_API bool IsClippedEx(const ImRect &bb, ImGuiID id)
Definition: imgui.cpp:4947
IMGUI_API void SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void *user_data=NULL)
Definition: imgui.cpp:4016
bool IsMouseKey(ImGuiKey key)
IMGUI_API void SetNextWindowBgAlpha(float alpha)
Definition: imgui.cpp:9041
static void DockNodePreviewDockRender(ImGuiWindow *host_window, ImGuiDockNode *host_node, ImGuiWindow *payload_window, const ImGuiDockPreviewData *preview_data)
Definition: imgui.cpp:19413
IMGUI_API void DockContextNewFrameUpdateUndocking(ImGuiContext *ctx)
Definition: imgui.cpp:17386
static bool UpdateTryMergeWindowIntoHostViewport(ImGuiWindow *window, ImGuiViewportP *host_viewport)
Definition: imgui.cpp:16190
IMGUI_API float GetColumnOffsetFromNorm(const ImGuiOldColumns *columns, float offset_norm)
IMGUI_API bool IsKeyDown(ImGuiKey key)
Definition: imgui.cpp:10134
static void NavUpdateCreateMoveRequest()
Definition: imgui.cpp:14311
IMGUI_API ImGuiWindow * FindWindowByID(ImGuiID id)
Definition: imgui.cpp:6685
IMGUI_API void MarkItemEdited(ImGuiID id)
Definition: imgui.cpp:4684
IMGUI_API ImFont * GetDefaultFont()
Definition: imgui.cpp:9337
IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow *window)
Definition: imgui.cpp:4578
IMGUI_API void SetWindowHitTestHole(ImGuiWindow *window, const ImVec2 &pos, const ImVec2 &size)
Definition: imgui.cpp:8947
IMGUI_API void ClearIniSettings()
Definition: imgui.cpp:15779
IMGUI_API ImVec2 CalcTextSize(const char *text, const char *text_end=NULL, bool hide_text_after_double_hash=false, float wrap_width=-1.0f)
Definition: imgui.cpp:6220
static ImGuiDockNode * DockNodeTreeFindVisibleNodeByPos(ImGuiDockNode *node, ImVec2 pos)
Definition: imgui.cpp:19877
IMGUI_API void ErrorCheckEndFrameFinalizeErrorTooltip()
Definition: imgui.cpp:11516
IMGUI_API void GetAllocatorFunctions(ImGuiMemAllocFunc *p_alloc_func, ImGuiMemFreeFunc *p_free_func, void **p_user_data)
Definition: imgui.cpp:4024
IMGUI_API void KeepAliveID(ImGuiID id)
Definition: imgui.cpp:11606
IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow *window, ImGuiWindowFlags flags, ImGuiWindow *parent_window)
Definition: imgui.cpp:7521
IMGUI_API void DebugNodeDockNode(ImGuiDockNode *node, const char *label)
Definition: imgui.cpp:22513
static int FindWindowFocusIndex(ImGuiWindow *window)
Definition: imgui.cpp:13196
IMGUI_API void EndTabBar()
IMGUI_API float GetCursorPosY()
Definition: imgui.cpp:11854
bool IsLegacyKey(ImGuiKey key)
IMGUI_API bool IsItemToggledSelection()
Definition: imgui.cpp:6386
IMGUI_API void NavMoveRequestApplyResult()
Definition: imgui.cpp:14456
IMGUI_API void TabItemBackground(ImDrawList *draw_list, const ImRect &bb, ImGuiTabItemFlags flags, ImU32 col)
IMGUI_API ImGuiTabItem * TabBarFindTabByID(ImGuiTabBar *tab_bar, ImGuiID tab_id)
IMGUI_API bool IsAnyItemFocused()
Definition: imgui.cpp:6408
IMGUI_API ImGuiViewport * GetWindowViewport()
Definition: imgui.cpp:9091
IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow *window)
Definition: imgui.cpp:13482
IMGUI_API void Dummy(const ImVec2 &size)
IMGUI_API bool IsItemDeactivatedAfterEdit()
Definition: imgui.cpp:6346
static void UpdateSettings()
Definition: imgui.cpp:15712
IMGUI_API void DebugNodeWindowsList(ImVector< ImGuiWindow * > *windows, const char *label)
Definition: imgui.cpp:23109
IMGUI_API void DockContextProcessUndockWindow(ImGuiContext *ctx, ImGuiWindow *window, bool clear_persistent_docking_ref=true)
Definition: imgui.cpp:17881
IMGUI_API void BringWindowToDisplayBehind(ImGuiWindow *window, ImGuiWindow *above_window)
Definition: imgui.cpp:13280
IMGUI_API void DockBuilderDockWindow(const char *window_name, ImGuiID node_id)
Definition: imgui.cpp:20122
IMGUI_API float GetFrameHeightWithSpacing()
Definition: imgui.cpp:12017
IMGUI_API void DebugNodeStorage(ImGuiStorage *storage, const char *label)
Definition: imgui.cpp:22924
IMGUI_API void LoadIniSettingsFromMemory(const char *ini_data, size_t ini_size=0)
Definition: imgui.cpp:15801
IMGUI_API ImGuiID GetWindowDockID()
Definition: imgui.cpp:8821
IMGUI_API ImVec2 GetCursorStartPos()
Definition: imgui.cpp:11884
static void DockNodeMoveWindows(ImGuiDockNode *dst_node, ImGuiDockNode *src_node)
Definition: imgui.cpp:18179
IMGUI_API void LogToFile(int auto_open_depth=-1, const char *filename=NULL)
Definition: imgui.cpp:15588
bool IsActiveIdUsingNavDir(ImGuiDir dir)
static void UpdateFontsNewFrame()
Definition: imgui.cpp:9304
IMGUI_API bool BeginDragDropTargetCustom(const ImRect &bb, ImGuiID id)
Definition: imgui.cpp:15304
static void RenderDimmedBackgroundBehindWindow(ImGuiWindow *window, ImU32 col)
Definition: imgui.cpp:5916
IMGUI_API void DockBuilderCopyNode(ImGuiID src_node_id, ImGuiID dst_node_id, ImVector< ImGuiID > *out_node_remap_pairs)
Definition: imgui.cpp:20391
IMGUI_API ImGuiID DockBuilderAddNode(ImGuiID node_id=0, ImGuiDockNodeFlags flags=0)
Definition: imgui.cpp:20182
IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow *window, ImGuiNavMoveFlags move_flags)
Definition: imgui.cpp:13912
IMGUI_API void DockNodeEndAmendTabBar()
Definition: imgui.cpp:18831
IMGUI_API void TextUnformatted(const char *text, const char *text_end=NULL)
IMGUI_API ImVec2 GetWindowContentRegionMax()
Definition: imgui.cpp:12046
static void DockNodeTreeMerge(ImGuiContext *ctx, ImGuiDockNode *parent_node, ImGuiDockNode *merge_lead_child)
Definition: imgui.cpp:19585
IMGUI_API void PopStyleColor(int count=1)
Definition: imgui.cpp:3521
IMGUI_API void ScrollToRect(ImGuiWindow *window, const ImRect &rect, ImGuiScrollFlags flags=0)
Definition: imgui.cpp:12201
IMGUI_API float GetWindowDpiScale()
Definition: imgui.cpp:9085
IMGUI_API ImDrawFlags CalcRoundingFlagsForRectInRect(const ImRect &r_in, const ImRect &r_outer, float threshold)
IMGUI_API void LogTextV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:15478
IMGUI_API void RenderText(ImVec2 pos, const char *text, const char *text_end=NULL, bool hide_text_after_hash=true)
Definition: imgui.cpp:3758
IMGUI_API bool IsWindowAppearing()
Definition: imgui.cpp:8971
IMGUI_API bool IsWindowChildOf(ImGuiWindow *window, ImGuiWindow *potential_parent, bool popup_hierarchy, bool dock_hierarchy)
Definition: imgui.cpp:8722
static void UpdateWindowInFocusOrderList(ImGuiWindow *window, bool just_created, ImGuiWindowFlags new_flags)
Definition: imgui.cpp:13206
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_window_flags)
Definition: imgui.cpp:12791
IMGUI_API void EndTable()
static void DockNodeAddWindow(ImGuiDockNode *node, ImGuiWindow *window, bool add_to_tab_bar)
Definition: imgui.cpp:18037
IMGUI_API void ErrorRecoveryTryToRecoverWindowState(const ImGuiErrorRecoveryState *state_in)
Definition: imgui.cpp:11387
IMGUI_API void OpenPopup(const char *str_id, ImGuiPopupFlags popup_flags=0)
Definition: imgui.cpp:12600
IMGUI_API void EndDisabled()
Definition: imgui.cpp:8645
IMGUI_API void Text(const char *fmt,...) IM_FMTARGS(1)
IMGUI_API bool DebugCheckVersionAndDataLayout(const char *version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx)
Definition: imgui.cpp:11146
IMGUI_API ImDrawList * GetWindowDrawList()
Definition: imgui.cpp:9079
static void WindowSyncOwnedViewport(ImGuiWindow *window, ImGuiWindow *parent_window_in_stack)
Definition: imgui.cpp:16788
IMGUI_API float GetTextLineHeightWithSpacing()
Definition: imgui.cpp:12005
IMGUI_API bool MenuItem(const char *label, const char *shortcut=NULL, bool selected=false, bool enabled=true)
static void NavProcessItem()
Definition: imgui.cpp:13695
IMGUI_API void EndMenuBar()
IMGUI_API bool Combo(const char *label, int *current_item, const char *const items[], int items_count, int popup_max_height_in_items=-1)
IMGUI_API ImGuiStorage * GetStateStorage()
Definition: imgui.cpp:9266
IMGUI_API void StartMouseMovingWindowOrNode(ImGuiWindow *window, ImGuiDockNode *node, bool undock)
Definition: imgui.cpp:5186
IMGUI_API ImVec2 CalcWindowNextAutoFitSize(ImGuiWindow *window)
Definition: imgui.cpp:6905
IMGUI_API ImGuiWindowSettings * FindWindowSettingsByWindow(ImGuiWindow *window)
Definition: imgui.cpp:15936
IMGUI_API void SetItemKeyOwner(ImGuiKey key)
Definition: imgui.cpp:11020
IMGUI_API void SetNavWindow(ImGuiWindow *window)
Definition: imgui.cpp:13440
IMGUI_API void SetClipboardText(const char *text)
Definition: imgui.cpp:5062
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char *text, const char *text_end, float wrap_width)
Definition: imgui.cpp:3784
IMGUI_API void DockContextQueueDock(ImGuiContext *ctx, ImGuiWindow *target, ImGuiDockNode *target_node, ImGuiWindow *payload, ImGuiDir split_dir, float split_ratio, bool split_outer)
Definition: imgui.cpp:17682
IMGUI_API void UpdateCurrentFontSize(float restore_font_size_after_scaling)
Definition: imgui.cpp:9408
IMGUI_API void LogText(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:15466
IMGUI_API void DebugNodeViewport(ImGuiViewportP *viewport)
Definition: imgui.cpp:22977
static void DockNodeStartMouseMovingWindow(ImGuiDockNode *node, ImGuiWindow *window)
Definition: imgui.cpp:18386
IMGUI_API void EndPopup()
Definition: imgui.cpp:12881
IMGUI_API ImVec2 TabItemCalcSize(const char *label, bool has_close_button_or_unsaved_marker)
static void DestroyViewport(ImGuiViewportP *viewport)
Definition: imgui.cpp:16624
IMGUI_API bool InputText(const char *label, char *buf, size_t buf_size, ImGuiInputTextFlags flags=0, ImGuiInputTextCallback callback=NULL, void *user_data=NULL)
const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID
Definition: imgui.cpp:1347
IMGUI_API ImGuiWindow * GetTopMostAndVisiblePopupModal()
Definition: imgui.cpp:12553
IMGUI_API bool BeginCombo(const char *label, const char *preview_value, ImGuiComboFlags flags=0)
IMGUI_API void PopItemFlag()
Definition: imgui.cpp:8611
IMGUI_API void TextDisabled(const char *fmt,...) IM_FMTARGS(1)
IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow *under_this_window, ImGuiWindow *ignore_window, ImGuiViewport *filter_viewport, ImGuiFocusRequestFlags flags)
Definition: imgui.cpp:13378
IMGUI_API ImVec2 GetWindowSize()
Definition: imgui.cpp:8888
IMGUI_API void DebugLog(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:23144
IMGUI_API void SetWindowPos(const ImVec2 &pos, ImGuiCond cond=0)
Definition: imgui.cpp:8876
IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)
Definition: imgui.cpp:13844
IMGUI_API void GcCompactTransientMiscBuffers()
Definition: imgui.cpp:4562
IMGUI_API bool DragFloat(const char *label, float *v, float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *format="%.3f", ImGuiSliderFlags flags=0)
IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val)
Definition: imgui.cpp:3591
static void NavUpdate()
Definition: imgui.cpp:14084
IMGUI_API float GetTextLineHeight()
Definition: imgui.cpp:11999
static void UpdateViewportsEndFrame()
Definition: imgui.cpp:16535
IMGUI_API void RemoveContextHook(ImGuiContext *context, ImGuiID hook_to_remove)
Definition: imgui.cpp:4478
IMGUI_API ImGuiDockNode * DockBuilderGetNode(ImGuiID node_id)
Definition: imgui.cpp:20148
IMGUI_API void UpdateWindowSkipRefresh(ImGuiWindow *window)
Definition: imgui.cpp:7544
IMGUI_API void InputTextDeactivateHook(ImGuiID id)
IMGUI_API void SetNextWindowContentSize(const ImVec2 &size)
Definition: imgui.cpp:9018
static void DockNodeCalcSplitRects(ImVec2 &pos_old, ImVec2 &size_old, ImVec2 &pos_new, ImVec2 &size_new, ImGuiDir dir, ImVec2 size_new_desired)
Definition: imgui.cpp:19239
IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0)
Definition: imgui.cpp:8775
IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float &out_h, float &out_s, float &out_v)
Definition: imgui.cpp:2763
ImGuiTableInstanceData * TableGetInstanceData(ImGuiTable *table, int instance_no)
static void UpdateDebugToolItemPicker()
Definition: imgui.cpp:23391
IMGUI_API void UpdateInputEvents(bool trickle_fast_inputs)
Definition: imgui.cpp:10780
int TabBarGetTabOrder(ImGuiTabBar *tab_bar, ImGuiTabItem *tab)
static ImGuiDockNode * DockContextAddNode(ImGuiContext *ctx, ImGuiID id)
Definition: imgui.cpp:17494
static void ErrorCheckNewFrameSanityChecks()
Definition: imgui.cpp:11199
IMGUI_API bool IsWindowContentHoverable(ImGuiWindow *window, ImGuiHoveredFlags flags=0)
Definition: imgui.cpp:4708
IMGUI_API void SetNextWindowSize(const ImVec2 &size, ImGuiCond cond=0)
Definition: imgui.cpp:8994
IMGUI_API float GetScrollMaxY()
Definition: imgui.cpp:12297
IMGUI_API void RenderTextClipped(const ImVec2 &pos_min, const ImVec2 &pos_max, const char *text, const char *text_end, const ImVec2 *text_size_if_known, const ImVec2 &align=ImVec2(0, 0), const ImRect *clip_rect=NULL)
Definition: imgui.cpp:3833
IMGUI_API float CalcItemWidth()
Definition: imgui.cpp:11958
IMGUI_API ImGuiID GetIDWithSeed(const char *str_id_begin, const char *str_id_end, ImGuiID seed)
Definition: imgui.cpp:9607
IMGUI_API bool IsKeyChordPressed(ImGuiKeyChord key_chord)
Definition: imgui.cpp:11026
IMGUI_API void NewFrame()
Definition: imgui.cpp:5508
IMGUI_API bool CheckboxFlags(const char *label, int *flags, int flags_value)
IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2 &ref_pos, const ImVec2 &size, ImGuiDir *last_dir, const ImRect &r_outer, const ImRect &r_avoid, ImGuiPopupPositionPolicy policy)
Definition: imgui.cpp:12981
IMGUI_API void ShowIDStackToolWindow(bool *p_open=NULL)
Definition: imgui.cpp:23530
IMGUI_API void Render()
Definition: imgui.cpp:6146
ImGuiDockNode * DockNodeGetRootNode(ImGuiDockNode *node)
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond=0)
Definition: imgui.cpp:8960
IMGUI_API void DockContextQueueUndockWindow(ImGuiContext *ctx, ImGuiWindow *window)
Definition: imgui.cpp:17696
IMGUI_API void DebugDrawLineExtents(ImU32 col=IM_COL32(255, 0, 0, 255))
Definition: imgui.cpp:23316
bool IsLRModKey(ImGuiKey key)
IMGUI_API ImDrawData * GetDrawData()
Definition: imgui.cpp:5101
IMGUI_API void DockBuilderRemoveNodeChildNodes(ImGuiID node_id)
Definition: imgui.cpp:20225
IMGUI_API void ScrollToItem(ImGuiScrollFlags flags=0)
Definition: imgui.cpp:12194
IMGUI_API void DebugNodeInputTextState(ImGuiInputTextState *state)
IMGUI_API void DestroyContext(ImGuiContext *ctx=NULL)
Definition: imgui.cpp:4042
IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate)
Definition: imgui.cpp:9831
static void UpdateKeyboardInputs()
Definition: imgui.cpp:10445
IMGUI_API void PopID()
Definition: imgui.cpp:9629
IMGUI_API void SetHoveredID(ImGuiID id)
Definition: imgui.cpp:4669
IMGUI_API ImGuiStyle & GetStyle()
Definition: imgui.cpp:3459
IMGUI_API void DebugStartItemPicker()
Definition: imgui.cpp:23384
IMGUI_API void TabItemLabelAndCloseButton(ImDrawList *draw_list, const ImRect &bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char *label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool *out_just_closed, bool *out_text_clipped)
IMGUI_API ImGuiWindow * FindWindowByName(const char *name)
Definition: imgui.cpp:6691
IMGUI_API void DebugNodeFontGlyphesForSrcMask(ImFont *font, ImFontBaked *baked, int src_mask)
Definition: imgui.cpp:22856
IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4 &in)
Definition: imgui.cpp:2751
IMGUI_API void DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size)
Definition: imgui.cpp:20164
IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags item_flags, ImGuiItemStatusFlags status_flags, const ImRect &item_rect)
Definition: imgui.cpp:4960
IMGUI_API ImVec2 GetMousePos()
Definition: imgui.cpp:10336
IMGUI_API void SetWindowDock(ImGuiWindow *window, ImGuiID dock_id, ImGuiCond cond)
Definition: imgui.cpp:19909
static float NavUpdatePageUpPageDown()
Definition: imgui.cpp:14627
IMGUI_API bool IsWindowDocked()
Definition: imgui.cpp:8827
IMGUI_API void SetCurrentFont(ImFont *font, float font_size_before_scaling, float font_size_after_scaling)
Definition: imgui.cpp:9386
IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags=ImGuiPopupFlags_None)
Definition: imgui.cpp:12617
IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard)
Definition: imgui.cpp:10738
IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup()
Definition: imgui.cpp:10354
IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags=0)
Definition: imgui.cpp:15125
IMGUI_API void SetNextWindowFocus()
Definition: imgui.cpp:13166
IMGUI_API void TabBarCloseTab(ImGuiTabBar *tab_bar, ImGuiTabItem *tab)
IMGUI_API bool DebugBreakButton(const char *label, const char *description_of_location)
Definition: imgui.cpp:22437
IMGUI_API bool BeginChildEx(const char *name, ImGuiID id, const ImVec2 &size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags)
Definition: imgui.cpp:6497
IMGUI_API void SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags=0)
Definition: imgui.cpp:10973
IMGUI_API bool BeginDragDropTarget()
Definition: imgui.cpp:15332
ImGuiWindow * GetCurrentWindow()
IMGUI_API float GetFontSize()
Definition: imgui.cpp:9111
IMGUI_API bool IsWindowAbove(ImGuiWindow *potential_above, ImGuiWindow *potential_below)
Definition: imgui.cpp:8751
IMGUI_API void ClearWindowSettings(const char *name)
Definition: imgui.cpp:15945
IMGUI_API void DebugNodeTabBar(ImGuiTabBar *tab_bar, const char *label)
Definition: imgui.cpp:22937
static void DockNodeAddTabBar(ImGuiDockNode *node)
Definition: imgui.cpp:19143
static void SetLastItemDataForWindow(ImGuiWindow *window, const ImRect &rect)
Definition: imgui.cpp:4969
IMGUI_API void SetWindowFocus()
Definition: imgui.cpp:13148
IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled)
Definition: imgui.cpp:8598
IMGUI_API void SetScrollHereY(float center_y_ratio=0.5f)
Definition: imgui.cpp:12381
IMGUI_API void EndTooltip()
Definition: imgui.cpp:12456
bool IsAliasKey(ImGuiKey key)
IMGUI_API void SetNextWindowViewport(ImGuiID viewport_id)
Definition: imgui.cpp:9048
IMGUI_API bool BeginErrorTooltip()
Definition: imgui.cpp:11569
IMGUI_API void ErrorRecoveryStoreState(ImGuiErrorRecoveryState *state_out)
Definition: imgui.cpp:11330
IMGUI_API bool TableNextColumn()
IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags=0)
Definition: imgui.cpp:4760
IMGUI_API void SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags)
Definition: imgui.cpp:9072
IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type)
Definition: imgui.cpp:10420
IMGUI_API void ShowFontAtlas(ImFontAtlas *atlas)
Definition: imgui.cpp:21546
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h)
Definition: imgui.cpp:11980
IMGUI_API void DebugDrawCursorPos(ImU32 col=IM_COL32(255, 0, 0, 255))
Definition: imgui.cpp:23306
IMGUI_API ImGuiWindow * FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow *window)
Definition: imgui.cpp:5955
bool IsGamepadKey(ImGuiKey key)
IMGUI_API void DockBuilderSetNodePos(ImGuiID node_id, ImVec2 pos)
Definition: imgui.cpp:20154
IMGUI_API int FindWindowDisplayIndex(ImGuiWindow *window)
Definition: imgui.cpp:13302
static void UpdateMouseInputs()
Definition: imgui.cpp:10512
IMGUI_API void LogBegin(ImGuiLogFlags flags, int auto_open_depth)
Definition: imgui.cpp:15549
IMGUI_API bool IsAnyItemActive()
Definition: imgui.cpp:6402
IMGUI_API void DebugDrawItemRect(ImU32 col=IM_COL32(255, 0, 0, 255))
Definition: imgui.cpp:23329
IMGUI_API void DebugBreakClearData()
Definition: imgui.cpp:22414
IMGUI_API void DestroyPlatformWindow(ImGuiViewportP *viewport)
Definition: imgui.cpp:17073
IMGUI_API void PushStyleVarX(ImGuiStyleVar idx, float val_x)
Definition: imgui.cpp:3605
static ImGuiDockNodeSettings * DockSettingsFindNodeSettings(ImGuiContext *ctx, ImGuiID node_id)
Definition: imgui.cpp:20888
IMGUI_API void PushOverrideID(ImGuiID id)
Definition: imgui.cpp:9593
static void NavUpdateWindowing()
Definition: imgui.cpp:14848
static void DockNodeHideHostWindow(ImGuiDockNode *node)
Definition: imgui.cpp:18221
static void DockNodeRemoveTabBar(ImGuiDockNode *node)
Definition: imgui.cpp:19149
IMGUI_API void PushFocusScope(ImGuiID id)
Definition: imgui.cpp:9132
IMGUI_API bool TestKeyOwner(ImGuiKey key, ImGuiID owner_id)
Definition: imgui.cpp:10940
IMGUI_API ImGuiID DockContextGenNodeID(ImGuiContext *ctx)
Definition: imgui.cpp:17483
IMGUI_API float GetNavTweakPressedAmount(ImGuiAxis axis)
Definition: imgui.cpp:14061
IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold=-1.0f)
Definition: imgui.cpp:10318
static void DockNodeTreeSplit(ImGuiContext *ctx, ImGuiDockNode *parent_node, ImGuiAxis split_axis, int split_first_child, float split_ratio, ImGuiDockNode *new_node)
Definition: imgui.cpp:19541
IMGUI_API void LogToTTY(int auto_open_depth=-1)
Definition: imgui.cpp:15575
IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio=0.5f)
Definition: imgui.cpp:12355
static void DockNodePreviewDockSetup(ImGuiWindow *host_window, ImGuiDockNode *host_node, ImGuiWindow *payload_window, ImGuiDockNode *payload_node, ImGuiDockPreviewData *preview_data, bool is_explicit_target, bool is_outer_docking)
Definition: imgui.cpp:19327
IMGUI_API void PopItemWidth()
Definition: imgui.cpp:11943
IMGUI_API void SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags=0)
Definition: imgui.cpp:11049
IMGUI_API void FocusItem()
Definition: imgui.cpp:9182
static void NavUpdateWindowingApplyFocus(ImGuiWindow *window)
Definition: imgui.cpp:14812
static ImGuiWindow * DockNodeFindWindowByID(ImGuiDockNode *node, ImGuiID id)
Definition: imgui.cpp:18273
IMGUI_API void TabBarAddTab(ImGuiTabBar *tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow *window)
IMGUI_API void DockBuilderCopyWindowSettings(const char *src_name, const char *dst_name)
Definition: imgui.cpp:20409
ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key)
IMGUI_API void Unindent(float indent_w=0.0f)
Definition: imgui.cpp:11898
IMGUI_API ImGuiID GetHoveredID()
Definition: imgui.cpp:4678
IMGUI_API void TextWrapped(const char *fmt,...) IM_FMTARGS(1)
IMGUI_API void DebugNodeFontGlyph(ImFont *font, const ImFontGlyph *glyph)
Definition: imgui.cpp:22907
IMGUI_API void ErrorCheckUsingSetCursorPosToExtendParentBoundaries()
Definition: imgui.cpp:11183
IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow *window)
Definition: imgui.cpp:4590
IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData *result)
Definition: imgui.cpp:13869
IMGUI_API const ImVec4 & GetStyleColorVec4(ImGuiCol idx)
Definition: imgui.cpp:3481
IMGUI_API void DebugNodeWindowSettings(ImGuiWindowSettings *settings)
Definition: imgui.cpp:23099
bool IsNamedKeyOrMod(ImGuiKey key)
IMGUI_API ImGuiSettingsHandler * FindSettingsHandler(const char *type_name)
Definition: imgui.cpp:15768
IMGUI_API void SetNavFocusScope(ImGuiID focus_scope_id)
Definition: imgui.cpp:9154
IMGUI_API bool IsItemDeactivated()
Definition: imgui.cpp:6338
static ImGuiDockNode * DockContextBindNodeToWindow(ImGuiContext *ctx, ImGuiWindow *window)
Definition: imgui.cpp:20550
static ImGuiViewportP * AddUpdateViewport(ImGuiWindow *window, ImGuiID id, const ImVec2 &platform_pos, const ImVec2 &size, ImGuiViewportFlags flags)
Definition: imgui.cpp:16557
IMGUI_API void SetWindowViewport(ImGuiWindow *window, ImGuiViewportP *viewport)
Definition: imgui.cpp:16166
IMGUI_API void DockContextClearNodes(ImGuiContext *ctx, ImGuiID root_id, bool clear_settings_refs)
Definition: imgui.cpp:17363
IMGUI_API void ClearDragDrop()
Definition: imgui.cpp:15094
IMGUI_API bool IsDragDropActive()
Definition: imgui.cpp:15088
IMGUI_API ImVec2 GetCursorScreenPos()
Definition: imgui.cpp:11826
static void UpdateViewportsNewFrame()
Definition: imgui.cpp:16287
static void DockContextPruneUnusedSettingsNodes(ImGuiContext *ctx)
Definition: imgui.cpp:17557
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding=0.0f)
Definition: imgui.cpp:3916
IMGUI_API void DockBuilderRemoveNodeDockedWindows(ImGuiID node_id, bool clear_settings_refs=true)
Definition: imgui.cpp:20295
IMGUI_API bool IsItemFocused()
Definition: imgui.cpp:6353
IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f)
Definition: imgui.cpp:11800
IMGUI_API void RenderMouseCursor(ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
Definition: imgui.cpp:3962
IMGUI_API void AddSettingsHandler(const ImGuiSettingsHandler *handler)
Definition: imgui.cpp:15754
IMGUI_API void DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_dockspace_id, ImVector< const char * > *in_window_remap_pairs)
Definition: imgui.cpp:20443
static bool DockNodeCalcDropRectsAndTestMousePos(const ImRect &parent, ImGuiDir dir, ImRect &out_draw, bool outer_docking, ImVec2 *test_mouse_pos)
Definition: imgui.cpp:19273
IMGUI_API void DebugNodeFont(ImFont *font)
Definition: imgui.cpp:22712
IMGUI_API bool IsMouseHoveringRect(const ImVec2 &r_min, const ImVec2 &r_max, bool clip=true)
Definition: imgui.cpp:10299
IMGUI_API bool GetWindowAlwaysWantOwnTabBar(ImGuiWindow *window)
Definition: imgui.cpp:20540
IMGUI_API void SetKeyOwnersForKeyChord(ImGuiKeyChord key, ImGuiID owner_id, ImGuiInputFlags flags=0)
Definition: imgui.cpp:10990
static void DockSettingsHandler_WriteAll(ImGuiContext *imgui_ctx, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buf)
Definition: imgui.cpp:20986
IMGUI_API void NavInitWindow(ImGuiWindow *window, bool force_reinit)
Definition: imgui.cpp:13978
static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable *rt)
Definition: imgui.cpp:9880
IMGUI_API void TeleportMousePos(const ImVec2 &pos)
Definition: imgui.cpp:10344
IMGUI_API void SetFontRasterizerDensity(float rasterizer_density)
Definition: imgui.cpp:9460
static int UpdateWindowManualResize(ImGuiWindow *window, const ImVec2 &size_auto_fit, int *border_hovered, int *border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect &visibility_rect)
Definition: imgui.cpp:7004
IMGUI_API bool IsMouseReleased(ImGuiMouseButton button)
Definition: imgui.cpp:10250
IMGUI_API float GetFrameHeight()
Definition: imgui.cpp:12011
IMGUI_API bool SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID owner_id)
Definition: imgui.cpp:10039
IMGUI_API void SetCursorPosX(float local_x)
Definition: imgui.cpp:11868
IMGUI_API bool BeginTabBarEx(ImGuiTabBar *tab_bar, const ImRect &bb, ImGuiTabBarFlags flags)
IMGUI_API void NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData *result, const ImGuiTreeNodeStackData *tree_node_data)
Definition: imgui.cpp:13878
IMGUI_API void EndDragDropTarget()
Definition: imgui.cpp:15432
IMGUI_API void SetKeyboardFocusHere(int offset=0)
Definition: imgui.cpp:9209
IMGUI_API void DebugLocateItemResolveWithLastItem()
Definition: imgui.cpp:23365
IMGUI_API void TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n=-1)
IMGUI_API void BeginDisabled(bool disabled=true)
Definition: imgui.cpp:8630
IMGUI_API void DebugNodeTable(ImGuiTable *table)
IMGUI_API void DockBuilderFinish(ImGuiID node_id)
Definition: imgui.cpp:20523
static ImGuiWindow * NavRestoreLastChildNavWindow(ImGuiWindow *window)
Definition: imgui.cpp:13936
IMGUI_API void CloseCurrentPopup()
Definition: imgui.cpp:12760
IMGUI_API void Shutdown()
Definition: imgui.cpp:4373
IMGUI_API bool BeginChild(const char *str_id, const ImVec2 &size=ImVec2(0, 0), ImGuiChildFlags child_flags=0, ImGuiWindowFlags window_flags=0)
Definition: imgui.cpp:6486
IMGUI_API void DestroyPlatformWindows()
Definition: imgui.cpp:17098
IMGUI_API void UpdatePlatformWindows()
Definition: imgui.cpp:16876
IMGUI_API void SetNextItemAllowOverlap()
Definition: imgui.cpp:6429
IMGUI_API ImGuiID GetWindowResizeBorderID(ImGuiWindow *window, ImGuiDir dir)
Definition: imgui.cpp:6992
IMGUI_API bool IsMouseDown(ImGuiMouseButton button)
Definition: imgui.cpp:10209
IMGUI_API void * MemAlloc(size_t size)
Definition: imgui.cpp:5009
IMGUI_API void MarkIniSettingsDirty()
Definition: imgui.cpp:15739
IMGUI_API void PopClipRect()
Definition: imgui.cpp:5901
static int FindPlatformMonitorForPos(const ImVec2 &pos)
Definition: imgui.cpp:17010
IMGUI_API bool BeginPopupContextWindow(const char *str_id=NULL, ImGuiPopupFlags popup_flags=1)
Definition: imgui.cpp:12948
IMGUI_API void ErrorRecoveryTryToRecoverState(const ImGuiErrorRecoveryState *state_in)
Definition: imgui.cpp:11349
IMGUI_API void ShowDebugLogWindow(bool *p_open=NULL)
Definition: imgui.cpp:23208
IMGUI_API void DockBuilderRemoveNode(ImGuiID node_id)
Definition: imgui.cpp:20205
IMGUI_API bool IsKeyReleased(ImGuiKey key)
Definition: imgui.cpp:10194
IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable *table)
IMGUI_API float GetScrollMaxX()
Definition: imgui.cpp:12291
IMGUI_API void DockContextQueueUndockNode(ImGuiContext *ctx, ImGuiDockNode *node)
Definition: imgui.cpp:17704
static void ErrorCheckEndFrameSanityChecks()
Definition: imgui.cpp:11310
IMGUI_API ImGuiContext * GetCurrentContext()
Definition: imgui.cpp:4002
IMGUI_API void DockContextProcessUndockNode(ImGuiContext *ctx, ImGuiDockNode *node)
Definition: imgui.cpp:17897
IMGUI_API void PopFont()
Definition: imgui.cpp:9485
IMGUI_API void UpdateHoveredWindowAndCaptureFlags(const ImVec2 &mouse_pos)
Definition: imgui.cpp:5360
IMGUI_API void DebugNodeDrawList(ImGuiWindow *window, ImGuiViewportP *viewport, const ImDrawList *draw_list, const char *label)
Definition: imgui.cpp:22572
static void DockNodeUpdateHasCentralNodeChild(ImGuiDockNode *node)
Definition: imgui.cpp:18358
IMGUI_API void DebugRenderViewportThumbnail(ImDrawList *draw_list, ImGuiViewportP *viewport, const ImRect &bb)
Definition: imgui.cpp:21324
IMGUI_API void DebugAllocHook(ImGuiDebugAllocInfo *info, int frame_count, void *ptr, size_t size)
Definition: imgui.cpp:5031
static void DockNodeApplyPosSizeToWindows(ImGuiDockNode *node)
Definition: imgui.cpp:18212
IMGUI_API void BulletText(const char *fmt,...) IM_FMTARGS(1)
IMGUI_API void EndChild()
Definition: imgui.cpp:6626
IMGUI_API void PushFont(ImFont *font, float font_size_base_unscaled)
Definition: imgui.cpp:9471
IMGUI_API void EndColumns()
IMGUI_API bool Selectable(const char *label, bool selected=false, ImGuiSelectableFlags flags=0, const ImVec2 &size=ImVec2(0, 0))
IMGUI_API void DebugLogV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:23152
IMGUI_API void SaveIniSettingsToDisk(const char *ini_filename)
Definition: imgui.cpp:15871
IMGUI_API bool DockContextCalcDropPosForDocking(ImGuiWindow *target, ImGuiDockNode *target_node, ImGuiWindow *payload_window, ImGuiDockNode *payload_node, ImGuiDir split_dir, bool split_outer, ImVec2 *out_pos)
Definition: imgui.cpp:17939
static ImGuiInputSource NavCalcPreferredRefPosSource()
Definition: imgui.cpp:14010
IMGUI_API void SetNextWindowPos(const ImVec2 &pos, ImGuiCond cond=0, const ImVec2 &pivot=ImVec2(0, 0))
Definition: imgui.cpp:8983
static void NavApplyItemToResult(ImGuiNavItemData *result)
Definition: imgui.cpp:13668
IMGUI_API void DebugNodeWindow(ImGuiWindow *window, const char *label)
Definition: imgui.cpp:23022
IMGUI_API void StartMouseMovingWindow(ImGuiWindow *window)
Definition: imgui.cpp:5161
IMGUI_API void DebugFlashStyleColor(ImGuiCol idx)
Definition: imgui.cpp:21489
static bool GetWindowAlwaysWantOwnViewport(ImGuiWindow *window)
Definition: imgui.cpp:16177
IMGUI_API void TabBarQueueReorder(ImGuiTabBar *tab_bar, ImGuiTabItem *tab, int offset)
IMGUI_API void ShowMetricsWindow(bool *p_open=NULL)
Definition: imgui.cpp:21732
IMGUI_API void SetNextWindowClass(const ImGuiWindowClass *window_class)
Definition: imgui.cpp:9063
IMGUI_API void SetNextFrameWantCaptureMouse(bool want_capture_mouse)
Definition: imgui.cpp:10744
IMGUI_API void BringWindowToFocusFront(ImGuiWindow *window)
Definition: imgui.cpp:13229
IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button)
Definition: imgui.cpp:10289
int strcmp(const String &s1, const String &s2)
Definition: relates.cpp:14
bool TestBit(int n) const
void SetBit(int n)
int size() const
T * alloc_chunk(size_t sz)
T * ptr_from_offset(int off)
T * next_chunk(T *p)
int offset_from_ptr(const T *p)
bool empty() const
ImTextureRef TexRef
Definition: imgui.h:3217
unsigned int VtxOffset
Definition: imgui.h:3218
ImVec4 ClipRect
Definition: imgui.h:3216
unsigned int ElemCount
Definition: imgui.h:3220
ImDrawCallback UserCallback
Definition: imgui.h:3221
unsigned int IdxOffset
Definition: imgui.h:3219
ImVector< ImDrawList * > * Layers[2]
ImVector< ImDrawList * > LayerData1
int TotalIdxCount
Definition: imgui.h:3483
ImVec2 DisplayPos
Definition: imgui.h:3486
ImVector< ImTextureData * > * Textures
Definition: imgui.h:3490
ImVec2 DisplaySize
Definition: imgui.h:3487
bool Valid
Definition: imgui.h:3481
ImVec2 FramebufferScale
Definition: imgui.h:3488
ImVector< ImDrawList * > CmdLists
Definition: imgui.h:3485
int CmdListsCount
Definition: imgui.h:3482
int TotalVtxCount
Definition: imgui.h:3484
ImGuiViewport * OwnerViewport
Definition: imgui.h:3489
ImGuiContext * Context
ImVector< ImVec2 > TempBuffer
ImDrawListFlags InitialFlags
ImFontAtlas * FontAtlas
void SetCircleTessellationMaxError(float max_error)
Definition: imgui_draw.cpp:407
IMGUI_API void PushClipRectFullScreen()
Definition: imgui_draw.cpp:670
IMGUI_API void _SetTexture(ImTextureRef tex_ref)
Definition: imgui_draw.cpp:699
ImDrawListSplitter _Splitter
Definition: imgui.h:3336
IMGUI_API void _PopUnusedDrawCmd()
Definition: imgui_draw.cpp:511
IMGUI_API void AddImage(ImTextureRef tex_ref, const ImVec2 &p_min, const ImVec2 &p_max, const ImVec2 &uv_min=ImVec2(0, 0), const ImVec2 &uv_max=ImVec2(1, 1), ImU32 col=IM_COL32_WHITE)
void ChannelsMerge()
Definition: imgui.h:3435
IMGUI_API void PushTexture(ImTextureRef tex_ref)
Definition: imgui_draw.cpp:682
IMGUI_API void PopClipRect()
Definition: imgui_draw.cpp:675
IMGUI_API void _ResetForNewFrame()
Definition: imgui_draw.cpp:445
IMGUI_API void PushClipRect(const ImVec2 &clip_rect_min, const ImVec2 &clip_rect_max, bool intersect_with_current_clip_rect=false)
Definition: imgui_draw.cpp:651
void PathStroke(ImU32 col, ImDrawFlags flags=0, float thickness=1.0f)
Definition: imgui.h:3405
IMGUI_API void _ClearFreeMemory()
Definition: imgui_draw.cpp:471
const char * _OwnerName
Definition: imgui.h:3341
IMGUI_API void _SetDrawListSharedData(ImDrawListSharedData *data)
Definition: imgui_draw.cpp:434
ImVector< ImDrawCmd > CmdBuffer
Definition: imgui.h:3324
IMGUI_API void AddRectFilled(const ImVec2 &p_min, const ImVec2 &p_max, ImU32 col, float rounding=0.0f, ImDrawFlags flags=0)
IMGUI_API void PathArcToFast(const ImVec2 &center, float radius, int a_min_of_12, int a_max_of_12)
void PathLineTo(const ImVec2 &pos)
Definition: imgui.h:3401
IMGUI_API void AddDrawCmd()
Definition: imgui_draw.cpp:497
IMGUI_API void AddLine(const ImVec2 &p1, const ImVec2 &p2, ImU32 col, float thickness=1.0f)
ImVector< ImDrawVert > VtxBuffer
Definition: imgui.h:3326
void ChannelsSetCurrent(int n)
Definition: imgui.h:3436
IMGUI_API void AddPolyline(const ImVec2 *points, int num_points, ImU32 col, ImDrawFlags flags, float thickness)
Definition: imgui_draw.cpp:801
IMGUI_API void AddText(const ImVec2 &pos, ImU32 col, const char *text_begin, const char *text_end=NULL)
void ChannelsSplit(int count)
Definition: imgui.h:3434
ImDrawListSharedData * _Data
Definition: imgui.h:3331
IMGUI_API void AddRect(const ImVec2 &p_min, const ImVec2 &p_max, ImU32 col, float rounding=0.0f, ImDrawFlags flags=0, float thickness=1.0f)
ImDrawListFlags Flags
Definition: imgui.h:3327
ImVector< ImDrawIdx > IdxBuffer
Definition: imgui.h:3325
IMGUI_API void PopTexture()
Definition: imgui_draw.cpp:691
ImVector< ImVec4 > _ClipRectStack
Definition: imgui.h:3337
void PathFillConvex(ImU32 col)
Definition: imgui.h:3403
IMGUI_API void AddTriangleFilled(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, ImU32 col)
IMGUI_API void PathArcTo(const ImVec2 &center, float radius, float a_min, float a_max, int num_segments=0)
ImU32 col
Definition: imgui.h:3239
ImVec2 uv
Definition: imgui.h:3238
ImVec2 pos
Definition: imgui.h:3237
ImStableVector< ImFontBaked, 32 > BakedPool
ImVector< ImFontAtlasRectEntry > RectsIndex
unsigned short y
Definition: imgui.h:3666
ImVec2 uv0
Definition: imgui.h:3668
unsigned short h
Definition: imgui.h:3667
unsigned short w
Definition: imgui.h:3667
ImVec2 uv1
Definition: imgui.h:3668
unsigned short x
Definition: imgui.h:3666
ImVector< ImFont * > Fonts
Definition: imgui.h:3817
bool Locked
Definition: imgui.h:3811
ImFontAtlasBuilder * Builder
Definition: imgui.h:3823
bool RendererHasTextures
Definition: imgui.h:3812
IMGUI_API bool GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect *out_r) const
IMGUI_API void CompactCache()
int RefCount
Definition: imgui.h:3828
IMGUI_API void RemoveFont(ImFont *font)
ImTextureRef TexRef
Definition: imgui.h:3805
const char * FontLoaderName
Definition: imgui.h:3825
unsigned int FontLoaderFlags
Definition: imgui.h:3827
ImGuiContext * OwnerContext
Definition: imgui.h:3829
IMGUI_API void SetFontLoader(const ImFontLoader *font_loader)
ImVector< ImTextureData * > TexList
Definition: imgui.h:3810
ImFontAtlasFlags Flags
Definition: imgui.h:3790
const ImFontLoader * FontLoader
Definition: imgui.h:3824
IMGUI_API bool IsGlyphLoaded(ImWchar c)
float RasterizerDensity
Definition: imgui.h:3856
unsigned int MetricsTotalSurface
Definition: imgui.h:3865
ImFont * ContainerFont
Definition: imgui.h:3870
ImVector< ImFontGlyph > Glyphs
Definition: imgui.h:3860
IMGUI_API float GetCharAdvance(ImWchar c)
float Ascent
Definition: imgui.h:3864
IMGUI_API ImFontGlyph * FindGlyph(ImWchar c)
float Size
Definition: imgui.h:3855
int LastUsedFrame
Definition: imgui.h:3868
float Descent
Definition: imgui.h:3864
char Name[40]
Definition: imgui.h:3589
ImVec2 GlyphOffset
Definition: imgui.h:3605
ImS8 OversampleH
Definition: imgui.h:3598
const ImFontLoader * FontLoader
Definition: imgui.h:3618
bool PixelSnapH
Definition: imgui.h:3596
ImS8 OversampleV
Definition: imgui.h:3599
unsigned int FontLoaderFlags
Definition: imgui.h:3610
float AdvanceX
Definition: imgui.h:3632
float X1
Definition: imgui.h:3633
float X0
Definition: imgui.h:3633
unsigned int Codepoint
Definition: imgui.h:3631
float V0
Definition: imgui.h:3634
float U0
Definition: imgui.h:3634
float V1
Definition: imgui.h:3634
unsigned int Visible
Definition: imgui.h:3629
unsigned int SourceIdx
Definition: imgui.h:3630
int PackId
Definition: imgui.h:3635
float Y1
Definition: imgui.h:3633
float U1
Definition: imgui.h:3634
float Y0
Definition: imgui.h:3633
const char * Name
float FontSizeAfterScaling
float FontSizeBeforeScaling
Definition: imgui.h:3898
IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char *text_begin, const char *text_end=NULL, const char **remaining=NULL)
IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
ImWchar EllipsisChar
Definition: imgui.h:3910
const char * GetDebugName() const
Definition: imgui.h:3924
float CurrentRasterizerDensity
Definition: imgui.h:3903
ImVector< ImFontConfig * > Sources
Definition: imgui.h:3909
IMGUI_API void RenderChar(ImDrawList *draw_list, float size, const ImVec2 &pos, ImU32 col, ImWchar c, const ImVec4 *cpu_fine_clip=NULL)
ImFontAtlas * ContainerAtlas
Definition: imgui.h:3901
IMGUI_API ImFontBaked * GetFontBaked(float font_size, float density=-1.0f)
bool IsLoaded() const
Definition: imgui.h:3923
ImWchar FallbackChar
Definition: imgui.h:3911
float Scale
Definition: imgui.h:3916
float LegacySize
Definition: imgui.h:3908
ImGuiWindow * Window
ImGuiContextHookType Type
ImGuiContextHookCallback Callback
ImGuiConfigFlags ConfigFlagsLastFrame
ImVec4 DebugFlashStyleColorBackup
ImGuiNavItemData NavInitResult
bool DebugShowGroupRects
ImGuiID DebugLocateId
int WantCaptureKeyboardNextFrame
int DragDropSourceFrameCount
ImGuiID DebugHookIdInfo
ImGuiID NavActivateDownId
ImGuiPlatformImeData PlatformImeData
ImGuiID HoveredIdPreviousFrame
ImGuiID HoverItemDelayId
ImGuiID DebugBreakInWindow
float FramerateSecPerFrame[60]
ImGuiKeyChord ConfigNavWindowingKeyPrev
ImVector< ImGuiPopupData > OpenPopupStack
ImVector< ImGuiWindow * > Windows
ImGuiViewportP * CurrentViewport
void * ErrorCallbackUserData
ImGuiNextWindowData NextWindowData
bool DebugItemPickerActive
bool HoveredIdAllowOverlap
ImPool< ImGuiMultiSelectState > MultiSelectStorage
ImChunkStream< ImGuiWindowSettings > SettingsWindows
ImGuiNavLayer NavLayer
ImGuiID NavJustMovedToId
ImGuiTypingSelectState TypingSelectState
ImVector< ImGuiWindow * > WindowsFocusOrder
ImGuiDir NavMoveDir
ImGuiSelectionUserData NavLastValidSelectionUserData
char ContextName[16]
ImVector< ImGuiWindow * > WindowsTempSortBuffer
ImGuiDebugAllocInfo DebugAllocInfo
float MouseStationaryTimer
ImGuiID NavActivatePressedId
float WindowsBorderHoverPadding
ImGuiWindow * MovingWindow
ImGuiKeyChord ConfigNavWindowingKeyNext
ImVec2 ActiveIdClickOffset
bool WindowResizeRelativeMode
ImU8 DebugItemPickerMouseButton
ImGuiItemFlags CurrentItemFlags
ImGuiDockNode * DebugHoveredDockNode
ImGuiWindow * TooltipPreviousWindow
bool ActiveIdUsingAllKeyboardKeys
int FrameCountPlatformEnded
ImGuiTextBuffer DebugLogBuf
const char * LocalizationTable[ImGuiLocKey_COUNT]
ImVector< ImGuiID > MenusIdSubmittedThisFrame
ImGuiStyle Style
bool NavHighlightItemUnderNav
ImGuiID WithinEndChildID
ImGuiErrorCallback ErrorCallback
ImGuiInputSource NavInputSource
ImGuiWindow * WheelingWindow
ImGuiInputSource ActiveIdSource
ImGuiMetricsConfig DebugMetricsConfig
bool NavWindowingToggleLayer
ImGuiPayload DragDropPayload
float WheelingWindowReleaseTimer
ImRect NavScoringRect
ImVec2 WheelingAxisAvg
ImGuiNextItemData NextItemData
float DisabledAlphaBackup
float NavWindowingTimer
ImGuiDebugLogFlags DebugLogFlags
ImGuiDir NavMoveClipDir
ImGuiLastItemData LastItemData
ImS8 DebugBeginReturnValueCullDepth
ImGuiID HoverItemUnlockedStationaryId
ImVector< ImTextureData * > UserTextures
int LogDepthToExpandDefault
const char * LogNextPrefix
ImGuiActivateFlags NavNextActivateFlags
float DragDropAcceptIdCurrRectSurface
ImGuiID HookIdNext
short DisabledStackSize
ImVector< ImGuiPopupData > BeginPopupStack
float FontRasterizerDensity
ImVector< ImGuiPtrOrIndex > CurrentTabBarStack
ImGuiScrollFlags NavMoveScrollFlags
ImVector< ImFontStackData > FontStack
ImGuiID HoverItemDelayIdPreviousFrame
ImRect WindowResizeBorderExpectedRect
int WheelingWindowScrolledFrame
ImGuiContext(ImFontAtlas *shared_font_atlas)
Definition: imgui.cpp:4071
ImGuiTextIndex DebugLogIndex
float NavWindowingHighlightAlpha
ImGuiNavItemData NavMoveResultLocal
ImGuiTextBuffer SettingsIniData
double LastKeyModsChangeTime
bool DragDropWithinSource
ImGuiID DebugDrawIdConflictsId
ImVector< ImGuiFocusScopeData > NavFocusRoute
bool HoveredIdIsDisabled
ImGuiInputTextDeactivatedState InputTextDeactivatedState
ImGuiDragDropFlags DragDropSourceFlags
bool ConfigNavWindowingWithGamepad
ImVector< ImGuiTableTempData > TablesTempData
bool NavJustMovedToHasSelectionData
int FramerateSecPerFrameIdx
int FramerateSecPerFrameCount
ImVector< ImGuiContextHook > Hooks
ImGuiNavItemData NavMoveResultOther
ImRect PlatformMonitorsFullWorkRect
bool NavJustMovedToIsTabbing
ImGuiID CurrentFocusScopeId
ImGuiKeyChord DebugBreakKeyChord
ImU32 ActiveIdUsingNavDirMask
ImRect DragDropTargetClipRect
ImGuiPlatformMonitor FallbackMonitor
ImGuiWindow * HoveredWindow
int MultiSelectTempDataStacked
ImVec2 NavWindowingAccumDeltaPos
ImDrawListSharedData DrawListSharedData
float LastActiveIdTimer
ImVec2 WheelingWindowWheelRemainder
ImGuiDragDropFlags DragDropAcceptFlags
float DebugFlashStyleColorTime
ImVector< ImGuiGroupData > GroupStack
float NavHighlightActivatedTimer
float SettingsDirtyTimer
int WantCaptureMouseNextFrame
ImGuiNavItemData NavTabbingResultFirst
ImGuiTextBuffer LogBuffer
ImGuiPlatformIO PlatformIO
ImGuiViewportP * MouseViewport
ImGuiID NavActivateId
int DragDropAcceptFrameCount
ImVector< ImGuiShrinkWidthItem > ShrinkWidthBuffer
ImGuiID DragDropHoldJustPressedId
ImGuiInputSource NavWindowingInputSource
ImVector< ImGuiItemFlags > ItemFlagsStack
ImGuiID LastActiveId
ImGuiWindow * LogWindow
const char * LogNextSuffix
int ClipperTempDataStacked
ImGuiID DebugItemPickerBreakId
ImGuiKeyOwnerData KeysOwnerData[ImGuiKey_NamedKey_COUNT]
ImGuiMouseSource InputEventsNextMouseSource
int ViewportFocusedStampCount
char TempKeychordName[64]
void(* DockNodeWindowMenuHandler)(ImGuiContext *ctx, ImGuiDockNode *node, ImGuiTabBar *tab_bar)
ImGuiID NavJustMovedFromFocusScopeId
ImVector< ImFontAtlas * > FontAtlases
ImPool< ImGuiTabBar > TabBars
ImGuiErrorRecoveryState * StackSizesInBeginForCurrentWindow
ImGuiWindow * NavWindowingTarget
ImGuiID ActiveIdIsAlive
bool NavInitRequestFromMove
ImGuiIDStackTool DebugIDStackTool
ImGuiDir NavMoveDirForDebug
ImGuiID HoverWindowUnlockedStationaryId
ImGuiWindow * ActiveIdWindow
double LastKeyboardKeyPressTime
ImVector< ImGuiWindowStackData > CurrentWindowStack
ImRect DragDropTargetRect
ImGuiID DebugBreakInTable
ImGuiKeyRoutingTable KeysRoutingTable
int ErrorCountCurrentFrame
ImGuiWindow * HoveredWindowBeforeClear
ImGuiErrorRecoveryState StackSizesInNewFrame
int DebugDrawIdConflictsCount
bool ActiveIdHasBeenPressedBefore
bool ActiveIdIsJustActivated
ImVector< ImGuiViewportP * > Viewports
ImGuiWindow * CurrentWindow
ImVector< ImGuiListClipperData > ClipperTempData
ImVector< float > TablesLastTimeActive
ImGuiWindow * NavWindowingListWindow
float HoverItemDelayClearTimer
ImGuiWindow * NavWindowingTargetAnim
ImU8 DebugLogAutoDisableFrames
bool WithinFrameScopeWithImplicitWindow
ImS8 NavCursorHideFrames
ImVector< char > ClipboardHandlerData
ImBitArrayForNamedKeys KeysMayBeCharInput
ImVector< char > TempBuffer
ImGuiDeactivatedItemData DeactivatedItemData
bool ActiveIdAllowOverlap
ImGuiCol DebugFlashStyleColorIdx
ImGuiMouseCursor MouseCursor
bool ActiveIdFromShortcut
ImGuiInputTextState InputTextState
ImGuiID PlatformLastFocusedViewportId
ImGuiID DragDropAcceptIdPrev
int PlatformWindowsCreatedCount
ImVec2 NavWindowingAccumDeltaSize
ImVec2 MouseLastValidPos
bool DragDropWithinTarget
ImVector< ImGuiStyleMod > StyleVarStack
ImGuiID NavNextActivateId
float FramerateSecPerFrameAccum
ImVector< ImDrawChannel > DrawChannelsTempMergeBuffer
int WantTextInputNextFrame
bool DebugBreakInLocateId
ImGuiKey NavWindowingToggleKey
unsigned char DragDropPayloadBufLocal[16]
ImGuiID NavFocusScopeId
float HoveredIdNotActiveTimer
ImGuiDebugLogFlags DebugLogAutoDisableFlags
ImGuiWindow * HoveredWindowUnderMovingWindow
bool ActiveIdHasBeenEditedBefore
int HoveredIdPreviousFrameItemCount
ImGuiLogFlags LogFlags
bool NavMoveForwardToNextFrame
ImGuiViewportP * MouseLastHoveredViewport
ImGuiPlatformImeData PlatformImeDataPrev
ImGuiBoxSelectState BoxSelectState
ImChunkStream< ImGuiTableSettings > SettingsTables
int WheelingWindowStartFrame
ImU32 InputEventsNextEventId
ImGuiKeyChord NavMoveKeyMods
ImGuiConfigFlags ConfigFlagsCurrFrame
ImGuiTable * CurrentTable
ImGuiStorage WindowsById
ImGuiKeyChord NavJustMovedToKeyMods
ImGuiMultiSelectTempData * CurrentMultiSelect
ImGuiDockContext DockContext
ImVector< ImGuiSettingsHandler > SettingsHandlers
ImFontBaked * FontBaked
ImRect NavScoringNoClipRect
ImGuiTabBar * CurrentTabBar
ImGuiWindow * NavWindow
ImGuiActivateFlags NavActivateFlags
bool TestEngineHookItems
ImVector< ImGuiColorMod > ColorStack
ImVector< ImGuiTreeNodeStackData > TreeNodeStack
ImGuiNavItemData NavMoveResultLocalVisible
ImGuiNavMoveFlags NavMoveFlags
ImVector< ImGuiFocusScopeData > FocusScopeStack
bool NavMoveScoringItems
ImVector< ImGuiInputEvent > InputEventsQueue
double LastKeyModsChangeFromNoneTime
short TooltipOverrideCount
bool ActiveIdHasBeenEditedThisFrame
ImVec2 ErrorTooltipLockedPos
float HoverItemDelayTimer
ImVec2 WheelingWindowRefMousePos
ImVector< ImGuiInputEvent > InputEventsTrail
bool ActiveIdNoClearOnFocusLoss
ImGuiID NavJustMovedToFocusScopeId
ImGuiID TempInputId
ImGuiID DragDropAcceptIdCurr
ImGuiKeyChord DebugBreakInShortcutRouting
ImGuiID NavHighlightActivatedId
ImVector< unsigned char > DragDropPayloadBufHeap
ImFileHandle LogFile
ImGuiID ActiveIdPreviousFrame
ImGuiID DragDropTargetId
ImPool< ImGuiTable > Tables
ImVector< ImGuiMultiSelectTempData > MultiSelectTempData
ImGuiDebugAllocEntry LastEntriesBuf[6]
ImVector< ImGuiDockRequest > Requests
ImVector< ImGuiDockNodeSettings > NodesSettings
ImGuiStorage Nodes
signed char SplitAxis
Definition: imgui.cpp:17237
ImGuiDockNodeFlags Flags
Definition: imgui.cpp:17239
ImGuiDockNode * CentralNode
Definition: imgui.cpp:18243
ImGuiDockNode * FirstNodeWithWindows
Definition: imgui.cpp:18244
ImGuiID SelectedTabId
ImRect Rect() const
ImGuiDataAuthority AuthorityForViewport
bool IsDockSpace() const
ImGuiDockNode * CentralNode
ImGuiID LastFocusedNodeId
ImGuiID WantCloseTabId
ImGuiWindow * HostWindow
bool WantHiddenTabBarToggle
ImGuiDockNode * ParentNode
ImGuiDockNode * ChildNodes[2]
bool IsFloatingNode() const
bool IsCentralNode() const
ImVector< ImGuiWindow * > Windows
ImGuiWindowClass WindowClass
ImGuiID RefViewportId
ImGuiDockNodeFlags MergedFlags
bool IsNoTabBar() const
void UpdateMergedFlags()
ImGuiDockNodeFlags LocalFlagsInWindows
bool IsHiddenTabBar() const
bool IsEmpty() const
ImGuiWindow * VisibleWindow
ImGuiTabBar * TabBar
ImGuiDataAuthority AuthorityForSize
bool IsLeafNode() const
ImGuiDockNodeFlags SharedFlags
ImGuiDockNodeFlags LocalFlags
bool IsRootNode() const
bool WantHiddenTabBarUpdate
ImGuiDataAuthority AuthorityForPos
ImGuiDockNode(ImGuiID id)
Definition: imgui.cpp:17989
ImGuiDockNode * OnlyNodeWithWindows
bool IsSplitNode() const
ImGuiAxis SplitAxis
ImGuiDockNodeState State
void SetLocalFlags(ImGuiDockNodeFlags flags)
ImGuiDockNode * SplitNode
Definition: imgui.cpp:17222
ImRect DropRectsDraw[ImGuiDir_COUNT+1]
Definition: imgui.cpp:17225
ImGuiDockNode FutureNode
Definition: imgui.cpp:17217
ImGuiDockNode * UndockTargetNode
Definition: imgui.cpp:17202
ImGuiWindow * DockPayload
Definition: imgui.cpp:17197
ImGuiDir DockSplitDir
Definition: imgui.cpp:17198
ImGuiDockNode * DockTargetNode
Definition: imgui.cpp:17196
ImGuiWindow * UndockTargetWindow
Definition: imgui.cpp:17201
ImGuiDockRequestType Type
Definition: imgui.cpp:17194
ImGuiWindow * DockTargetWindow
Definition: imgui.cpp:17195
float DockSplitRatio
Definition: imgui.cpp:17199
float BackupCurrLineTextBaseOffset
ImVec2 BackupCursorPosPrevLine
ImGuiID BackupActiveIdIsAlive
ImVec2 BackupCursorMaxPos
ImVec2 BackupCurrLineSize
ImVec1 BackupGroupOffset
bool BackupDeactivatedIdIsAlive
ImVector< ImGuiStackLevelInfo > Results
ImGuiTextBuffer ResultPathBuf
ImVec2 DisplaySize
Definition: imgui.h:2426
IMGUI_API void AddFocusEvent(bool focused)
Definition: imgui.cpp:1952
bool WantCaptureMouseUnlessPopupClose
Definition: imgui.h:2620
bool ConfigErrorRecoveryEnableDebugLog
Definition: imgui.h:2507
IMGUI_API void AddInputCharacterUTF16(ImWchar16 c)
Definition: imgui.cpp:1637
IMGUI_API ImGuiIO()
Definition: imgui.cpp:1523
bool ConfigDebugBeginReturnValueOnce
Definition: imgui.h:2527
bool ConfigWindowsCopyContentsWithCtrlC
Definition: imgui.h:2475
IMGUI_API void AddInputCharacter(unsigned int c)
Definition: imgui.cpp:1620
bool WantTextInput
Definition: imgui.h:2585
ImVec2 MousePosPrev
Definition: imgui.h:2621
ImFont * FontDefault
Definition: imgui.h:2436
float MouseDoubleClickMaxDist
Definition: imgui.h:2482
void * ClipboardUserData
Definition: imgui.h:2661
bool ConfigDockingAlwaysTabBar
Definition: imgui.h:2451
bool ConfigWindowsMoveFromTitleBarOnly
Definition: imgui.h:2474
int MetricsRenderIndices
Definition: imgui.h:2592
bool KeyAlt
Definition: imgui.h:2614
void(* SetClipboardTextFn)(void *user_data, const char *text)
Definition: imgui.h:2660
float MouseWheel
Definition: imgui.h:2608
ImVec2 MouseClickedPos[5]
Definition: imgui.h:2622
bool ConfigErrorRecoveryEnableTooltip
Definition: imgui.h:2508
ImFontAtlas * Fonts
Definition: imgui.h:2435
float MouseWheelH
Definition: imgui.h:2609
bool ConfigDebugHighlightIdConflictsShowItemPicker
Definition: imgui.h:2521
bool ConfigNavMoveSetMousePos
Definition: imgui.h:2441
bool ConfigScrollbarScrollByPage
Definition: imgui.h:2476
float KeyRepeatDelay
Definition: imgui.h:2484
bool MouseReleased[5]
Definition: imgui.h:2628
IMGUI_API void AddMouseWheelEvent(float wheel_x, float wheel_y)
Definition: imgui.cpp:1903
bool KeyShift
Definition: imgui.h:2613
ImVec2 MouseDragMaxDistanceAbs[5]
Definition: imgui.h:2636
bool WantCaptureKeyboard
Definition: imgui.h:2584
ImWchar16 InputQueueSurrogate
Definition: imgui.h:2641
ImVector< ImWchar > InputQueueCharacters
Definition: imgui.h:2642
float DeltaTime
Definition: imgui.h:2428
IMGUI_API void AddKeyEvent(ImGuiKey key, bool down)
Definition: imgui.cpp:1799
bool KeyCtrl
Definition: imgui.h:2612
const char * BackendPlatformName
Definition: imgui.h:2545
float MouseDownDurationPrev[5]
Definition: imgui.h:2635
ImVec2 MouseDelta
Definition: imgui.h:2595
IMGUI_API void ClearInputKeys()
Definition: imgui.cpp:1692
bool MouseDownOwnedUnlessPopupClose[5]
Definition: imgui.h:2631
bool ConfigNavSwapGamepadButtons
Definition: imgui.h:2440
ImGuiConfigFlags ConfigFlags
Definition: imgui.h:2424
IMGUI_API void AddMouseViewportEvent(ImGuiID id)
Definition: imgui.cpp:1931
bool ConfigDebugIgnoreFocusLoss
Definition: imgui.h:2533
bool ConfigDebugBeginReturnValueLoop
Definition: imgui.h:2528
bool MouseDownOwned[5]
Definition: imgui.h:2630
bool WantSaveIniSettings
Definition: imgui.h:2587
IMGUI_API void SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index=-1)
Definition: imgui.cpp:1809
void * BackendPlatformUserData
Definition: imgui.h:2547
bool ConfigNavEscapeClearFocusWindow
Definition: imgui.h:2444
bool ConfigNavCaptureKeyboard
Definition: imgui.h:2442
bool AppFocusLost
Definition: imgui.h:2639
ImVec2 DisplayFramebufferScale
Definition: imgui.h:2427
bool ConfigDebugIsDebuggerPresent
Definition: imgui.h:2514
bool ConfigDpiScaleFonts
Definition: imgui.h:2462
float FontGlobalScale
Definition: imgui.h:2655
ImGuiKeyChord KeyMods
Definition: imgui.h:2618
bool ConfigViewportsNoDecoration
Definition: imgui.h:2457
bool ConfigDockingTransparentPayload
Definition: imgui.h:2452
bool ConfigNavEscapeClearFocusItem
Definition: imgui.h:2443
IMGUI_API void ClearInputCharacters()
Definition: imgui.cpp:1730
bool MouseClicked[5]
Definition: imgui.h:2624
float MouseDragMaxDistanceSqr[5]
Definition: imgui.h:2637
bool WantSetMousePos
Definition: imgui.h:2586
const char * IniFilename
Definition: imgui.h:2430
bool ConfigNavCursorVisibleAuto
Definition: imgui.h:2445
bool MouseDoubleClicked[5]
Definition: imgui.h:2625
void * UserData
Definition: imgui.h:2432
float Framerate
Definition: imgui.h:2590
IMGUI_API void SetAppAcceptingEvents(bool accepting_events)
Definition: imgui.cpp:1822
int MetricsRenderVertices
Definition: imgui.h:2591
bool ConfigDragClickToInputText
Definition: imgui.h:2472
bool MouseDown[5]
Definition: imgui.h:2607
ImGuiContext * Ctx
Definition: imgui.h:2601
bool NavVisible
Definition: imgui.h:2589
ImGuiBackendFlags BackendFlags
Definition: imgui.h:2425
const char *(* GetClipboardTextFn)(void *user_data)
Definition: imgui.h:2659
bool MouseDrawCursor
Definition: imgui.h:2467
float IniSavingRate
Definition: imgui.h:2429
bool MouseCtrlLeftAsRightClick
Definition: imgui.h:2633
bool ConfigNavCursorVisibleAlways
Definition: imgui.h:2446
void * BackendRendererUserData
Definition: imgui.h:2548
bool ConfigErrorRecovery
Definition: imgui.h:2505
IMGUI_API void ClearInputMouse()
Definition: imgui.cpp:1709
IMGUI_API void AddMouseButtonEvent(int button, bool down)
Definition: imgui.cpp:1854
bool ConfigErrorRecoveryEnableAssert
Definition: imgui.h:2506
bool NavActive
Definition: imgui.h:2588
bool ConfigWindowsResizeFromEdges
Definition: imgui.h:2473
bool AppAcceptingEvents
Definition: imgui.h:2640
bool ConfigMacOSXBehaviors
Definition: imgui.h:2468
bool ConfigDebugIniSettings
Definition: imgui.h:2536
float MouseDownDuration[5]
Definition: imgui.h:2634
IMGUI_API void AddMousePosEvent(float x, float y)
Definition: imgui.cpp:1828
bool ConfigViewportsNoAutoMerge
Definition: imgui.h:2455
bool ConfigInputTextEnterKeepActive
Definition: imgui.h:2471
IMGUI_API void AddInputCharactersUTF8(const char *str)
Definition: imgui.cpp:1671
ImU16 MouseClickedCount[5]
Definition: imgui.h:2626
bool ConfigDockingWithShift
Definition: imgui.h:2450
IMGUI_API void AddKeyAnalogEvent(ImGuiKey key, bool down, float v)
Definition: imgui.cpp:1759
bool MouseWheelRequestAxisSwap
Definition: imgui.h:2632
float KeyRepeatRate
Definition: imgui.h:2485
bool ConfigDockingNoSplit
Definition: imgui.h:2449
const char * BackendRendererName
Definition: imgui.h:2546
bool ConfigInputTextCursorBlink
Definition: imgui.h:2470
ImVec2 MousePos
Definition: imgui.h:2606
void * BackendLanguageUserData
Definition: imgui.h:2549
float MouseDragThreshold
Definition: imgui.h:2483
float PenPressure
Definition: imgui.h:2638
IMGUI_API void AddMouseSourceEvent(ImGuiMouseSource source)
Definition: imgui.cpp:1924
ImGuiMouseSource MouseSource
Definition: imgui.h:2610
bool ConfigViewportsNoDefaultParent
Definition: imgui.h:2458
int MetricsActiveWindows
Definition: imgui.h:2594
bool ConfigDebugHighlightIdConflicts
Definition: imgui.h:2520
const char * LogFilename
Definition: imgui.h:2431
ImGuiID MouseHoveredViewport
Definition: imgui.h:2611
int MetricsRenderWindows
Definition: imgui.h:2593
double MouseReleasedTime[5]
Definition: imgui.h:2629
float ConfigMemoryCompactTimer
Definition: imgui.h:2477
float MouseDoubleClickTime
Definition: imgui.h:2481
ImU16 MouseClickedLastCount[5]
Definition: imgui.h:2627
IMGUI_API void ClearEventsQueue()
Definition: imgui.cpp:1684
bool ConfigInputTrickleEventQueue
Definition: imgui.h:2469
bool ConfigDpiScaleViewports
Definition: imgui.h:2463
bool WantCaptureMouse
Definition: imgui.h:2583
bool FontAllowUserScaling
Definition: imgui.h:2437
bool ConfigViewportsNoTaskBarIcon
Definition: imgui.h:2456
double MouseClickedTime[5]
Definition: imgui.h:2623
bool KeySuper
Definition: imgui.h:2615
ImGuiKeyData KeysData[ImGuiKey_NamedKey_COUNT]
Definition: imgui.h:2619
ImGuiMouseSource MouseSource
ImGuiMouseSource MouseSource
ImGuiMouseSource MouseSource
ImGuiInputEventType Type
ImGuiInputEventAppFocused AppFocused
ImGuiInputEventKey Key
ImGuiInputEventMouseButton MouseButton
ImGuiInputSource Source
ImGuiInputEventMouseWheel MouseWheel
ImGuiInputEventMousePos MousePos
ImGuiInputEventMouseViewport MouseViewport
ImGuiInputEventText Text
bool Down
Definition: imgui.h:2412
float DownDurationPrev
Definition: imgui.h:2414
float DownDuration
Definition: imgui.h:2413
float AnalogValue
Definition: imgui.h:2415
ImGuiKeyRoutingIndex NextEntryIndex
ImVector< ImGuiKeyRoutingData > Entries
ImVector< ImGuiKeyRoutingData > EntriesNext
ImGuiKeyRoutingIndex Index[ImGuiKey_NamedKey_COUNT]
ImGuiItemStatusFlags StatusFlags
ImGuiItemFlags ItemFlags
ImGuiKeyChord Shortcut
void Reset(ImGuiListClipper *clipper)
ImVector< ImGuiListClipperRange > Ranges
static ImGuiListClipperRange FromPositions(float y1, float y2, int off_min, int off_max)
static ImGuiListClipperRange FromIndices(int min, int max)
float ItemsHeight
Definition: imgui.h:2916
IMGUI_API void End()
Definition: imgui.cpp:3232
double StartPosY
Definition: imgui.h:2917
ImGuiContext * Ctx
Definition: imgui.h:2912
void * TempData
Definition: imgui.h:2919
IMGUI_API void Begin(int items_count, float items_height=-1.0f)
Definition: imgui.cpp:3203
IMGUI_API void IncludeItemsByIndex(int item_begin, int item_end)
Definition: imgui.cpp:3255
IMGUI_API void SeekCursorForItem(int item_index)
Definition: imgui.cpp:3266
double StartSeekOffsetY
Definition: imgui.h:2918
int DisplayStart
Definition: imgui.h:2913
IMGUI_API bool Step()
Definition: imgui.cpp:3432
IMGUI_API ~ImGuiListClipper()
Definition: imgui.cpp:3198
IMGUI_API ImGuiListClipper()
Definition: imgui.cpp:3193
const char * Text
ImGuiLocKey Key
void Update(float spacing, bool window_reappearing)
ImGuiMultiSelectState * Storage
ImGuiSelectionUserData SelectionUserData
ImGuiWindow * Window
ImGuiItemFlags ItemFlags
ImGuiKeyChord Shortcut
ImGuiInputFlags ShortcutFlags
ImGuiItemFlags ItemFlags
ImGuiNextItemDataFlags HasFlags
ImGuiSelectionUserData SelectionUserData
ImGuiNextWindowDataFlags HasFlags
ImGuiWindowRefreshFlags RefreshFlagsVal
ImGuiChildFlags ChildFlags
ImGuiWindowClass WindowClass
ImGuiSizeCallback SizeCallback
ImGuiOldColumnFlags Flags
ImVector< ImGuiOldColumnData > Columns
ImGuiID SourceParentId
Definition: imgui.h:2753
bool Preview
Definition: imgui.h:2756
bool IsPreview() const
Definition: imgui.h:2762
bool Delivery
Definition: imgui.h:2757
int DataSize
Definition: imgui.h:2749
char DataType[32+1]
Definition: imgui.h:2755
bool IsDataType(const char *type) const
Definition: imgui.h:2761
void Clear()
Definition: imgui.h:2760
ImGuiID SourceId
Definition: imgui.h:2752
int DataFrameCount
Definition: imgui.h:2754
bool IsDelivery() const
Definition: imgui.h:2763
void * Data
Definition: imgui.h:2748
void(* Renderer_SwapBuffers)(ImGuiViewport *vp, void *render_arg)
Definition: imgui.h:4164
ImVec2(* Platform_GetWindowSize)(ImGuiViewport *vp)
Definition: imgui.h:4144
void(* Platform_OnChangedViewport)(ImGuiViewport *vp)
Definition: imgui.h:4155
bool(* Platform_OpenInShellFn)(ImGuiContext *ctx, const char *path)
Definition: imgui.h:4097
void(* Platform_SetWindowPos)(ImGuiViewport *vp, ImVec2 pos)
Definition: imgui.h:4141
void(* Platform_SetWindowSize)(ImGuiViewport *vp, ImVec2 size)
Definition: imgui.h:4143
void(* Platform_SwapBuffers)(ImGuiViewport *vp, void *render_arg)
Definition: imgui.h:4153
ImVector< ImGuiViewport * > Viewports
Definition: imgui.h:4181
void(* Platform_RenderWindow)(ImGuiViewport *vp, void *render_arg)
Definition: imgui.h:4152
void(* Platform_SetWindowAlpha)(ImGuiViewport *vp, float alpha)
Definition: imgui.h:4150
ImVec2(* Platform_GetWindowPos)(ImGuiViewport *vp)
Definition: imgui.h:4142
ImVec2(* Platform_GetWindowFramebufferScale)(ImGuiViewport *vp)
Definition: imgui.h:4145
ImVector< ImTextureData * > Textures
Definition: imgui.h:4177
void(* Renderer_SetWindowSize)(ImGuiViewport *vp, ImVec2 size)
Definition: imgui.h:4162
void(* Platform_SetImeDataFn)(ImGuiContext *ctx, ImGuiViewport *viewport, ImGuiPlatformImeData *data)
Definition: imgui.h:4102
void(* Renderer_CreateWindow)(ImGuiViewport *vp)
Definition: imgui.h:4160
ImWchar Platform_LocaleDecimalPoint
Definition: imgui.h:4108
const char *(* Platform_GetClipboardTextFn)(ImGuiContext *ctx)
Definition: imgui.h:4091
void(* Platform_SetClipboardTextFn)(ImGuiContext *ctx, const char *text)
Definition: imgui.h:4092
bool(* Platform_GetWindowMinimized)(ImGuiViewport *vp)
Definition: imgui.h:4148
float(* Platform_GetWindowDpiScale)(ImGuiViewport *vp)
Definition: imgui.h:4154
void(* Platform_SetWindowTitle)(ImGuiViewport *vp, const char *str)
Definition: imgui.h:4149
ImVector< ImGuiPlatformMonitor > Monitors
Definition: imgui.h:4169
void(* Renderer_RenderWindow)(ImGuiViewport *vp, void *render_arg)
Definition: imgui.h:4163
void(* Platform_UpdateWindow)(ImGuiViewport *vp)
Definition: imgui.h:4151
IMGUI_API ImGuiPlatformIO()
Definition: imgui.cpp:1970
ImVec4(* Platform_GetWindowWorkAreaInsets)(ImGuiViewport *vp)
Definition: imgui.h:4156
void(* Platform_SetWindowFocus)(ImGuiViewport *vp)
Definition: imgui.h:4146
bool(* Platform_GetWindowFocus)(ImGuiViewport *vp)
Definition: imgui.h:4147
void(* Platform_CreateWindow)(ImGuiViewport *vp)
Definition: imgui.h:4138
void(* Platform_ShowWindow)(ImGuiViewport *vp)
Definition: imgui.h:4140
void(* Platform_DestroyWindow)(ImGuiViewport *vp)
Definition: imgui.h:4139
void(* Renderer_DestroyWindow)(ImGuiViewport *vp)
Definition: imgui.h:4161
ImGuiID ViewportId
Definition: imgui.h:4202
ImGuiWindow * RestoreNavWindow
ImGuiWindow * Window
void(* ReadLineFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, void *entry, const char *line)
void(* ReadInitFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler)
void(* ClearAllFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler)
void *(* ReadOpenFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, const char *name)
void(* ApplyAllFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler)
void(* WriteAllFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, ImGuiTextBuffer *out_buf)
ImGuiDataType DataType
ImGuiID key
Definition: imgui.h:2838
void * val_p
Definition: imgui.h:2839
IMGUI_API float GetFloat(ImGuiID key, float default_val=0.0f) const
Definition: imgui.cpp:2866
IMGUI_API bool GetBool(ImGuiID key, bool default_val=false) const
Definition: imgui.cpp:2861
IMGUI_API int * GetIntRef(ImGuiID key, int default_val=0)
Definition: imgui.cpp:2883
IMGUI_API void ** GetVoidPtrRef(ImGuiID key, void *default_val=NULL)
Definition: imgui.cpp:2904
IMGUI_API float * GetFloatRef(ImGuiID key, float default_val=0.0f)
Definition: imgui.cpp:2896
IMGUI_API void SetVoidPtr(ImGuiID key, void *val)
Definition: imgui.cpp:2936
IMGUI_API void BuildSortByKey()
Definition: imgui.cpp:2848
ImVector< ImGuiStoragePair > Data
Definition: imgui.h:2856
void Clear()
Definition: imgui.h:2861
IMGUI_API void * GetVoidPtr(ImGuiID key) const
Definition: imgui.cpp:2874
IMGUI_API void SetFloat(ImGuiID key, float val)
Definition: imgui.cpp:2927
IMGUI_API void SetBool(ImGuiID key, bool val)
Definition: imgui.cpp:2922
IMGUI_API int GetInt(ImGuiID key, int default_val=0) const
Definition: imgui.cpp:2853
IMGUI_API void SetAllInt(int val)
Definition: imgui.cpp:2945
IMGUI_API bool * GetBoolRef(ImGuiID key, bool default_val=false)
Definition: imgui.cpp:2891
IMGUI_API void SetInt(ImGuiID key, int val)
Definition: imgui.cpp:2913
ImGuiStyleVar VarIdx
float BackupFloat[2]
void * GetVarPtr(void *parent) const
ImGuiDataType DataType
float ScrollbarRounding
Definition: imgui.h:2339
bool AntiAliasedLines
Definition: imgui.h:2365
float GrabMinSize
Definition: imgui.h:2340
ImVec2 WindowMinSize
Definition: imgui.h:2322
float FrameRounding
Definition: imgui.h:2330
ImVec2 ButtonTextAlign
Definition: imgui.h:2356
ImVec2 ItemInnerSpacing
Definition: imgui.h:2333
float WindowBorderHoverPadding
Definition: imgui.h:2321
bool AntiAliasedFill
Definition: imgui.h:2367
float FrameBorderSize
Definition: imgui.h:2331
float TabRounding
Definition: imgui.h:2344
float TabBorderSize
Definition: imgui.h:2345
ImVec4 Colors[ImGuiCol_COUNT]
Definition: imgui.h:2372
ImGuiHoveredFlags HoverFlagsForTooltipNav
Definition: imgui.h:2380
float IndentSpacing
Definition: imgui.h:2336
ImVec2 WindowPadding
Definition: imgui.h:2318
float DockingSeparatorSize
Definition: imgui.h:2363
float _NextFrameFontSizeBase
Definition: imgui.h:2384
ImVec2 WindowTitleAlign
Definition: imgui.h:2323
float CurveTessellationTol
Definition: imgui.h:2368
float GrabRounding
Definition: imgui.h:2341
float PopupRounding
Definition: imgui.h:2327
float _MainScale
Definition: imgui.h:2383
float WindowBorderSize
Definition: imgui.h:2320
float ChildBorderSize
Definition: imgui.h:2326
float FontScaleDpi
Definition: imgui.h:2314
float MouseCursorScale
Definition: imgui.h:2364
ImGuiDir ColorButtonPosition
Definition: imgui.h:2355
ImVec2 ItemSpacing
Definition: imgui.h:2332
float LogSliderDeadzone
Definition: imgui.h:2342
IMGUI_API void ScaleAllSizes(float scale_factor)
Definition: imgui.cpp:1488
float SeparatorTextBorderSize
Definition: imgui.h:2358
float TabCloseButtonMinWidthSelected
Definition: imgui.h:2346
float ImageBorderSize
Definition: imgui.h:2343
ImVec2 DisplaySafeAreaPadding
Definition: imgui.h:2362
float ColumnsMinSpacing
Definition: imgui.h:2337
float TreeLinesRounding
Definition: imgui.h:2354
float ScrollbarSize
Definition: imgui.h:2338
float Alpha
Definition: imgui.h:2316
ImGuiHoveredFlags HoverFlagsForTooltipMouse
Definition: imgui.h:2379
float HoverDelayNormal
Definition: imgui.h:2378
ImGuiTreeNodeFlags TreeLinesFlags
Definition: imgui.h:2352
ImVec2 CellPadding
Definition: imgui.h:2334
float TreeLinesSize
Definition: imgui.h:2353
ImVec2 DisplayWindowPadding
Definition: imgui.h:2361
IMGUI_API ImGuiStyle()
Definition: imgui.cpp:1409
ImVec2 SeparatorTextAlign
Definition: imgui.h:2359
ImVec2 TouchExtraPadding
Definition: imgui.h:2335
ImGuiDir WindowMenuButtonPosition
Definition: imgui.h:2324
float ChildRounding
Definition: imgui.h:2325
float FontSizeBase
Definition: imgui.h:2312
ImVec2 TableAngledHeadersTextAlign
Definition: imgui.h:2351
float PopupBorderSize
Definition: imgui.h:2328
float DisabledAlpha
Definition: imgui.h:2317
float CircleTessellationMaxError
Definition: imgui.h:2369
float HoverStationaryDelay
Definition: imgui.h:2376
bool AntiAliasedLinesUseTex
Definition: imgui.h:2366
float WindowRounding
Definition: imgui.h:2319
float TabCloseButtonMinWidthUnselected
Definition: imgui.h:2347
float FontScaleMain
Definition: imgui.h:2313
ImVec2 SeparatorTextPadding
Definition: imgui.h:2360
float TableAngledHeadersAngle
Definition: imgui.h:2350
ImVec2 SelectableTextAlign
Definition: imgui.h:2357
ImVec2 FramePadding
Definition: imgui.h:2329
float HoverDelayShort
Definition: imgui.h:2377
float TabBarBorderSize
Definition: imgui.h:2348
float TabBarOverlineSize
Definition: imgui.h:2349
float ScrollingRectMaxX
ImGuiID VisibleTabId
ImGuiID SelectedTabId
ImVector< ImGuiTabItem > Tabs
ImGuiWindow * Window
ImGuiTabBarFlags Flags
ImGuiID NextSelectedTabId
float ScrollingRectMinX
ImGuiTabItemFlags Flags
ImGuiWindow * Window
ImRect BgClipRect
ImGuiTableColumnIdx HoveredColumnBody
ImRect HostClipRect
ImRect InnerClipRect
ImSpan< ImGuiTableColumn > Columns
ImRect InnerRect
ImRect OuterRect
ImS16 InstanceCurrent
ImGuiWindow * OuterWindow
ImGuiWindow * InnerWindow
void resize(int size)
Definition: imgui.h:2827
IMGUI_API void appendf(const char *fmt,...) IM_FMTARGS(2)
Definition: imgui.cpp:3083
int size() const
Definition: imgui.h:2824
static IMGUI_API char EmptyString[1]
Definition: imgui.h:2818
IMGUI_API void append(const char *str, const char *str_end=NULL)
Definition: imgui.cpp:3065
void clear()
Definition: imgui.h:2826
ImVector< char > Buf
Definition: imgui.h:2817
const char * c_str() const
Definition: imgui.h:2829
IMGUI_API void appendfv(const char *fmt, va_list args) IM_FMTLIST(2)
Definition: imgui.cpp:3092
const char * begin() const
Definition: imgui.h:2822
bool empty() const
Definition: imgui.h:2825
IMGUI_API void split(char separator, ImVector< ImGuiTextRange > *out) const
Definition: imgui.cpp:2978
ImVector< ImGuiTextRange > Filters
Definition: imgui.h:2809
IMGUI_API bool PassFilter(const char *text, const char *text_end=NULL) const
Definition: imgui.cpp:3016
IMGUI_API ImGuiTextFilter(const char *default_filter="")
Definition: imgui.cpp:2957
IMGUI_API bool Draw(const char *label="Filter (inc,-exc)", float width=0.0f)
Definition: imgui.cpp:2968
char InputBuf[256]
Definition: imgui.h:2808
IMGUI_API void Build()
Definition: imgui.cpp:2996
const char * get_line_end(const char *base, int n)
void append(const char *base, int old_size, int new_size)
Definition: imgui.cpp:3118
const char * get_line_begin(const char *base, int n)
ImGuiItemFlags ItemFlags
ImDrawList * BgFgDrawLists[2]
ImDrawDataBuilder DrawDataBuilder
ImVec2 BuildWorkInsetMax
ImGuiWindow * Window
void ClearRequestFlags()
ImVec2 BuildWorkInsetMin
int BgFgDrawListsLastFrame[2]
ImDrawData DrawDataP
ImRect GetMainRect() const
ImRect GetWorkRect() const
bool LastFocusedHadNavWindow
void * PlatformUserData
Definition: imgui.h:4014
ImGuiViewportFlags Flags
Definition: imgui.h:3998
ImVec2 Pos
Definition: imgui.h:3999
ImGuiID ParentViewportId
Definition: imgui.h:4005
ImGuiID ID
Definition: imgui.h:3997
ImVec2 FramebufferScale
Definition: imgui.h:4001
bool PlatformRequestMove
Definition: imgui.h:4018
bool PlatformWindowCreated
Definition: imgui.h:4017
float DpiScale
Definition: imgui.h:4004
ImVec2 WorkPos
Definition: imgui.h:4002
void * PlatformHandle
Definition: imgui.h:4015
void * RendererUserData
Definition: imgui.h:4013
void * PlatformHandleRaw
Definition: imgui.h:4016
ImVec2 Size
Definition: imgui.h:4000
ImVec2 WorkSize
Definition: imgui.h:4003
bool PlatformRequestClose
Definition: imgui.h:4020
ImDrawData * DrawData
Definition: imgui.h:4006
bool PlatformRequestResize
Definition: imgui.h:4019
ImVec2 GetCenter() const
Definition: imgui.h:4026
ImGuiDockNodeFlags DockNodeFlagsOverrideSet
Definition: imgui.h:2737
ImGuiID ClassId
Definition: imgui.h:2731
ImGuiViewportFlags ViewportFlagsOverrideSet
Definition: imgui.h:2734
ImGuiViewportFlags ViewportFlagsOverrideClear
Definition: imgui.h:2735
ImGuiID FocusRouteParentWindowId
Definition: imgui.h:2733
bool DockingAlwaysTabBar
Definition: imgui.h:2738
ImGuiID ParentViewportId
Definition: imgui.h:2732
bool DockingAllowUnclassed
Definition: imgui.h:2739
ImGuiTabItemFlags TabItemFlagsOverrideSet
Definition: imgui.h:2736
ImU32 Colors[ImGuiWindowDockStyleCol_COUNT]
ImGuiLastItemData ParentLastItemDataBackup
float DisabledOverrideReenableAlphaBackup
ImGuiErrorRecoveryState StackSizesInBegin
ImGuiItemStatusFlags DockTabItemStatusFlags
ImGuiLayoutType LayoutType
ImGuiMenuColumns MenuColumns
ImGuiItemStatusFlags WindowItemStatusFlags
ImGuiNavLayer NavLayerCurrent
ImVector< float > TextWrapPosStack
ImVector< float > ItemWidthStack
ImVector< ImGuiWindow * > ChildWindows
ImGuiItemStatusFlags ChildItemStatusFlags
ImGuiOldColumns * CurrentColumns
ImGuiStorage * StateStorage
ImGuiLayoutType ParentLayoutType
ImGuiWindowClass WindowClass
ImVec2 ScrollbarSizes
ImRect TitleBarRect() const
ImGuiContext * Ctx
bool DockNodeIsVisible
ImGuiCond SetWindowSizeAllowFlags
int ViewportAllowPlatformMonitorExtend
int MemoryDrawListVtxCapacity
ImRect Rect() const
float DecoOuterSizeX2
short BeginCountPreviousFrame
ImVector< ImGuiID > IDStack
ImGuiID NavLastIds[ImGuiNavLayer_COUNT]
ImGuiStorage StateStorage
ImS8 DisableInputsFrames
signed char ResizeBorderHeld
ImGuiChildFlags ChildFlags
ImGuiDockNode * DockNodeAsHost
ImDrawList * DrawList
bool WantCollapseToggle
ImVec2 ScrollTargetCenterRatio
ImGuiID GetIDFromRectangle(const ImRect &r_abs)
Definition: imgui.cpp:9552
ImGuiID GetIDFromPos(const ImVec2 &p_abs)
Definition: imgui.cpp:9543
ImU8 ScrollbarXStabilizeToggledHistory
ImGuiCond SetWindowCollapsedAllowFlags
float DecoOuterSizeX1
ImVec2 SetWindowPosPivot
ImVec2 WindowPadding
float FontWindowScale
ImRect InnerClipRect
ImRect MenuBarRect() const
ImGuiWindow * RootWindowPopupTree
ImGuiID NavRootFocusScopeId
float ItemWidthDefault
ImGuiWindow * ParentWindow
ImS8 HiddenFramesForRenderOnly
ImVec2ih HitTestHoleOffset
ImVec2 ContentSize
ImVec2 SetWindowPosVal
ImGuiWindow * NavLastChildNavWindow
ImS8 HiddenFramesCannotSkipItems
ImGuiWindowTempData DC
ImVec2 ScrollTarget
ImGuiWindowFlags Flags
signed char ResizeBorderHovered
ImGuiWindow * ParentWindowForFocusRoute
float WindowRounding
ImGuiWindowFlags FlagsPreviousFrame
~ImGuiWindow()
Definition: imgui.cpp:4534
ImGuiCond SetWindowPosAllowFlags
ImGuiWindow * RootWindowForNav
int MemoryDrawListIdxCapacity
ImGuiDockNode * DockNode
float DecoInnerSizeX1
ImGuiWindow * ParentWindowInBeginStack
ImVec2 ScrollTargetEdgeSnapDist
short BeginOrderWithinParent
ImGuiDir AutoPosLastDirection
ImVec2 ContentSizeExplicit
ImDrawList DrawListInst
ImVec2ih HitTestHoleSize
ImVec2 ContentSizeIdeal
ImRect NavRectRel[ImGuiNavLayer_COUNT]
float TitleBarHeight
ImGuiViewportP * Viewport
float DecoInnerSizeY1
ImVec2 ViewportPos
ImGuiID ViewportId
ImVec2 NavPreferredScoringPosRel[ImGuiNavLayer_COUNT]
ImRect OuterRectClipped
float FontWindowScaleParents
float DecoOuterSizeY1
ImGuiWindow(ImGuiContext *context, const char *name)
Definition: imgui.cpp:4502
float WindowBorderSize
float DecoOuterSizeY2
ImGuiWindowDockStyle DockStyle
ImVector< ImGuiOldColumns > ColumnsStorage
ImRect ParentWorkRect
bool ScrollbarXStabilizeEnabled
ImGuiWindow * RootWindowDockTree
ImGuiWindow * RootWindowForTitleBarHighlight
ImRect ContentRegionRect
float LastTimeActive
ImGuiCond SetWindowDockAllowFlags
ImGuiWindow * RootWindow
ImS8 HiddenFramesCanSkipItems
short BeginOrderWithinContext
int LastFrameJustFocused
ImGuiID GetID(const char *str, const char *str_end=NULL)
Definition: imgui.cpp:9505
T * GetByIndex(ImPoolIdx n)
int GetAliveCount() const
T * TryGetMapData(ImPoolIdx n)
T * GetOrAddByKey(ImGuiID key)
int GetMapSize() const
void Clear()
void Reserve(int capacity)
T * GetByKey(ImGuiID key)
bool Overlaps(const ImRect &r) const
bool IsInverted() const
void TranslateX(float dx)
ImVec4 ToVec4() const
void ClipWithFull(const ImRect &r)
ImVec2 GetBL() const
void Add(const ImVec2 &p)
float GetHeight() const
void Translate(const ImVec2 &d)
bool ContainsWithPad(const ImVec2 &p, const ImVec2 &pad) const
ImVec2 Max
ImVec2 GetCenter() const
void TranslateY(float dy)
void ClipWith(const ImRect &r)
bool Contains(const ImVec2 &p) const
ImVec2 GetBR() const
ImVec2 GetSize() const
void Expand(const float amount)
ImVec2 Min
float GetWidth() const
unsigned short RefCount
Definition: imgui.h:3560
ImTextureRect UsedRect
Definition: imgui.h:3556
ImTextureStatus Status
Definition: imgui.h:3548
bool UseColors
Definition: imgui.h:3561
bool WantDestroyNextFrame
Definition: imgui.h:3562
ImTextureFormat Format
Definition: imgui.h:3551
int UniqueID
Definition: imgui.h:3547
ImTextureID TexID
Definition: imgui.h:3550
int Height
Definition: imgui.h:3553
void * BackendUserData
Definition: imgui.h:3549
ImTextureRef GetTexRef()
Definition: imgui.h:3573
unsigned short x
Definition: imgui.h:3533
unsigned short h
Definition: imgui.h:3534
unsigned short y
Definition: imgui.h:3533
unsigned short w
Definition: imgui.h:3534
ImTextureID GetTexID() const
Definition: imgui.h:3945
ImTextureData * _TexData
Definition: imgui.h:371
Definition: imgui.h:293
float y
Definition: imgui.h:294
float x
Definition: imgui.h:294
Definition: imgui.h:306
float x
Definition: imgui.h:307
float y
Definition: imgui.h:307
float z
Definition: imgui.h:307
float w
Definition: imgui.h:307
void reserve(int new_capacity)
Definition: imgui.h:2279
void push_front(const T &v)
Definition: imgui.h:2285
T & back()
Definition: imgui.h:2271
bool contains(const T &v) const
Definition: imgui.h:2290
T * erase(const T *it)
Definition: imgui.h:2286
void pop_back()
Definition: imgui.h:2284
int index_from_ptr(const T *it) const
Definition: imgui.h:2296
T * find(const T &v)
Definition: imgui.h:2291
bool find_erase(const T &v)
Definition: imgui.h:2294
T * insert(const T *it, const T &v)
Definition: imgui.h:2289
bool empty() const
Definition: imgui.h:2257
void push_back(const T &v)
Definition: imgui.h:2283
T * begin()
Definition: imgui.h:2265
int Size
Definition: imgui.h:2238
int Capacity
Definition: imgui.h:2239
T * Data
Definition: imgui.h:2240
void clear_destruct()
Definition: imgui.h:2255
void resize(int new_size)
Definition: imgui.h:2276
int size_in_bytes() const
Definition: imgui.h:2259
void clear()
Definition: imgui.h:2253
void clear_delete()
Definition: imgui.h:2254
void swap(ImVector< T > &rhs)
Definition: imgui.h:2273
int open(const char *, int)
Opens a file descriptor.